From 6894dca64c04936d07048c0e8cbf7e25858548c3 Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 10 Jan 2014 03:41:59 +0000 Subject: Move lib into src --- src/lib/algo_base/algo_base.h | 41 + src/lib/algo_base/buf_comp.h | 171 ++++ src/lib/algo_base/info.txt | 8 + src/lib/algo_base/key_spec.h | 95 +++ src/lib/algo_base/scan_name.cpp | 222 +++++ src/lib/algo_base/scan_name.h | 108 +++ src/lib/algo_base/sym_algo.h | 97 +++ src/lib/algo_base/symkey.cpp | 133 +++ src/lib/algo_base/symkey.h | 143 ++++ src/lib/algo_base/transform.h | 99 +++ src/lib/algo_factory/algo_cache.h | 239 ++++++ src/lib/algo_factory/algo_factory.cpp | 352 ++++++++ src/lib/algo_factory/algo_factory.h | 225 +++++ src/lib/algo_factory/info.txt | 24 + src/lib/algo_factory/prov_weight.cpp | 34 + src/lib/alloc/info.txt | 3 + src/lib/alloc/locking_allocator/info.txt | 9 + .../alloc/locking_allocator/locking_allocator.cpp | 262 ++++++ .../alloc/locking_allocator/locking_allocator.h | 44 + src/lib/alloc/secmem.h | 185 +++++ src/lib/asn1/alg_id.cpp | 105 +++ src/lib/asn1/alg_id.h | 49 ++ src/lib/asn1/asn1_alt_name.cpp | 241 ++++++ src/lib/asn1/asn1_alt_name.h | 47 ++ src/lib/asn1/asn1_attribute.cpp | 60 ++ src/lib/asn1/asn1_attribute.h | 36 + src/lib/asn1/asn1_obj.cpp | 68 ++ src/lib/asn1/asn1_obj.h | 124 +++ src/lib/asn1/asn1_oid.cpp | 189 +++++ src/lib/asn1/asn1_oid.h | 96 +++ src/lib/asn1/asn1_str.cpp | 148 ++++ src/lib/asn1/asn1_str.h | 38 + src/lib/asn1/asn1_time.cpp | 303 +++++++ src/lib/asn1/asn1_time.h | 57 ++ src/lib/asn1/ber_dec.cpp | 561 +++++++++++++ src/lib/asn1/ber_dec.h | 260 ++++++ src/lib/asn1/der_enc.cpp | 410 +++++++++ src/lib/asn1/der_enc.h | 137 +++ src/lib/asn1/info.txt | 10 + src/lib/asn1/oid_lookup/default.cpp | 243 ++++++ src/lib/asn1/oid_lookup/info.txt | 5 + src/lib/asn1/oid_lookup/oids.cpp | 133 +++ src/lib/asn1/oid_lookup/oids.h | 65 ++ src/lib/asn1/x509_dn.cpp | 311 +++++++ src/lib/asn1/x509_dn.h | 56 ++ src/lib/benchmark/benchmark.cpp | 161 ++++ src/lib/benchmark/benchmark.h | 58 ++ src/lib/benchmark/info.txt | 11 + src/lib/block/aes/aes.cpp | 752 +++++++++++++++++ src/lib/block/aes/aes.h | 77 ++ src/lib/block/aes/info.txt | 1 + src/lib/block/aes_ni/aes_ni.cpp | 795 ++++++++++++++++++ src/lib/block/aes_ni/aes_ni.h | 77 ++ src/lib/block/aes_ni/info.txt | 9 + src/lib/block/aes_ssse3/aes_ssse3.cpp | 608 ++++++++++++++ src/lib/block/aes_ssse3/aes_ssse3.h | 71 ++ src/lib/block/aes_ssse3/info.txt | 17 + src/lib/block/block_cipher.h | 162 ++++ src/lib/block/blowfish/blfs_tab.cpp | 190 +++++ src/lib/block/blowfish/blowfish.cpp | 195 +++++ src/lib/block/blowfish/blowfish.h | 53 ++ src/lib/block/blowfish/info.txt | 1 + src/lib/block/camellia/camellia.cpp | 394 +++++++++ src/lib/block/camellia/camellia.h | 71 ++ src/lib/block/camellia/camellia_sbox.h | 545 ++++++++++++ src/lib/block/camellia/info.txt | 9 + src/lib/block/cascade/cascade.cpp | 98 +++ src/lib/block/cascade/cascade.h | 58 ++ src/lib/block/cascade/info.txt | 9 + src/lib/block/cast/cast128.cpp | 376 +++++++++ src/lib/block/cast/cast128.h | 40 + src/lib/block/cast/cast256.cpp | 228 +++++ src/lib/block/cast/cast256.h | 36 + src/lib/block/cast/cast_sboxes.h | 197 +++++ src/lib/block/cast/info.txt | 10 + src/lib/block/des/des.cpp | 304 +++++++ src/lib/block/des/des.h | 70 ++ src/lib/block/des/des_tab.cpp | 636 ++++++++++++++ src/lib/block/des/desx.cpp | 62 ++ src/lib/block/des/desx.h | 35 + src/lib/block/des/info.txt | 1 + src/lib/block/gost_28147/gost_28147.cpp | 177 ++++ src/lib/block/gost_28147/gost_28147.h | 84 ++ src/lib/block/gost_28147/info.txt | 1 + src/lib/block/idea/idea.cpp | 169 ++++ src/lib/block/idea/idea.h | 46 ++ src/lib/block/idea/info.txt | 1 + src/lib/block/idea_sse2/idea_sse2.cpp | 234 ++++++ src/lib/block/idea_sse2/idea_sse2.h | 31 + src/lib/block/idea_sse2/info.txt | 7 + src/lib/block/info.txt | 5 + src/lib/block/kasumi/info.txt | 1 + src/lib/block/kasumi/kasumi.cpp | 234 ++++++ src/lib/block/kasumi/kasumi.h | 35 + src/lib/block/lion/info.txt | 6 + src/lib/block/lion/lion.cpp | 129 +++ src/lib/block/lion/lion.h | 67 ++ src/lib/block/lubyrack/info.txt | 5 + src/lib/block/lubyrack/lubyrack.cpp | 129 +++ src/lib/block/lubyrack/lubyrack.h | 50 ++ src/lib/block/mars/info.txt | 1 + src/lib/block/mars/mars.cpp | 393 +++++++++ src/lib/block/mars/mars.h | 35 + src/lib/block/misty1/info.txt | 1 + src/lib/block/misty1/misty1.cpp | 270 ++++++ src/lib/block/misty1/misty1.h | 41 + src/lib/block/noekeon/info.txt | 1 + src/lib/block/noekeon/noekeon.cpp | 212 +++++ src/lib/block/noekeon/noekeon.h | 50 ++ src/lib/block/noekeon_simd/info.txt | 7 + src/lib/block/noekeon_simd/noekeon_simd.cpp | 177 ++++ src/lib/block/noekeon_simd/noekeon_simd.h | 31 + src/lib/block/rc2/info.txt | 1 + src/lib/block/rc2/rc2.cpp | 182 ++++ src/lib/block/rc2/rc2.h | 42 + src/lib/block/rc5/info.txt | 1 + src/lib/block/rc5/rc5.cpp | 135 +++ src/lib/block/rc5/rc5.h | 42 + src/lib/block/rc6/info.txt | 1 + src/lib/block/rc6/rc6.cpp | 145 ++++ src/lib/block/rc6/rc6.h | 35 + src/lib/block/safer/info.txt | 1 + src/lib/block/safer/safer_sk.cpp | 256 ++++++ src/lib/block/safer/safer_sk.h | 42 + src/lib/block/seed/info.txt | 1 + src/lib/block/seed/seed.cpp | 146 ++++ src/lib/block/seed/seed.h | 43 + src/lib/block/seed/seed_tab.cpp | 192 +++++ src/lib/block/serpent/info.txt | 13 + src/lib/block/serpent/serpent.cpp | 205 +++++ src/lib/block/serpent/serpent.h | 51 ++ src/lib/block/serpent/serpent_sbox.h | 428 ++++++++++ src/lib/block/serpent_simd/info.txt | 15 + src/lib/block/serpent_simd/serp_simd.cpp | 216 +++++ src/lib/block/serpent_simd/serp_simd.h | 31 + src/lib/block/serpent_x86_32/info.txt | 12 + src/lib/block/serpent_x86_32/serp_x86_32.cpp | 88 ++ src/lib/block/serpent_x86_32/serp_x86_32.h | 31 + src/lib/block/serpent_x86_32/serp_x86_32_imp.S | 669 +++++++++++++++ src/lib/block/skipjack/info.txt | 1 + src/lib/block/skipjack/skipjack.cpp | 200 +++++ src/lib/block/skipjack/skipjack.h | 35 + src/lib/block/square/info.txt | 1 + src/lib/block/square/sqr_tab.cpp | 460 +++++++++++ src/lib/block/square/square.cpp | 221 +++++ src/lib/block/square/square.h | 52 ++ src/lib/block/tea/info.txt | 1 + src/lib/block/tea/tea.cpp | 78 ++ src/lib/block/tea/tea.h | 34 + src/lib/block/threefish/info.txt | 1 + src/lib/block/threefish/threefish.cpp | 205 +++++ src/lib/block/threefish/threefish.h | 43 + src/lib/block/threefish_avx2/info.txt | 3 + src/lib/block/threefish_avx2/threefish_avx2.cpp | 341 ++++++++ src/lib/block/threefish_avx2/threefish_avx2.h | 28 + src/lib/block/twofish/info.txt | 1 + src/lib/block/twofish/two_tab.cpp | 293 +++++++ src/lib/block/twofish/twofish.cpp | 245 ++++++ src/lib/block/twofish/twofish.h | 47 ++ src/lib/block/xtea/info.txt | 1 + src/lib/block/xtea/xtea.cpp | 146 ++++ src/lib/block/xtea/xtea.h | 40 + src/lib/block/xtea_simd/info.txt | 7 + src/lib/block/xtea_simd/xtea_simd.cpp | 130 +++ src/lib/block/xtea_simd/xtea_simd.h | 30 + src/lib/cert/cvc/asn1_eac_str.cpp | 127 +++ src/lib/cert/cvc/asn1_eac_tm.cpp | 293 +++++++ src/lib/cert/cvc/cvc_ado.cpp | 127 +++ src/lib/cert/cvc/cvc_ado.h | 98 +++ src/lib/cert/cvc/cvc_cert.cpp | 135 +++ src/lib/cert/cvc/cvc_cert.h | 116 +++ src/lib/cert/cvc/cvc_gen_cert.h | 180 ++++ src/lib/cert/cvc/cvc_req.cpp | 53 ++ src/lib/cert/cvc/cvc_req.h | 59 ++ src/lib/cert/cvc/cvc_self.cpp | 340 ++++++++ src/lib/cert/cvc/cvc_self.h | 170 ++++ src/lib/cert/cvc/eac_asn_obj.h | 238 ++++++ src/lib/cert/cvc/eac_obj.h | 55 ++ src/lib/cert/cvc/ecdsa_sig.cpp | 59 ++ src/lib/cert/cvc/ecdsa_sig.h | 61 ++ src/lib/cert/cvc/info.txt | 36 + src/lib/cert/cvc/signed_obj.cpp | 96 +++ src/lib/cert/cvc/signed_obj.h | 96 +++ src/lib/cert/x509/cert_status.h | 56 ++ src/lib/cert/x509/certstor.cpp | 148 ++++ src/lib/cert/x509/certstor.h | 89 ++ src/lib/cert/x509/crl_ent.cpp | 103 +++ src/lib/cert/x509/crl_ent.h | 95 +++ src/lib/cert/x509/info.txt | 10 + src/lib/cert/x509/key_constraint.cpp | 69 ++ src/lib/cert/x509/key_constraint.h | 57 ++ src/lib/cert/x509/ocsp.cpp | 251 ++++++ src/lib/cert/x509/ocsp.h | 61 ++ src/lib/cert/x509/ocsp_types.cpp | 121 +++ src/lib/cert/x509/ocsp_types.h | 67 ++ src/lib/cert/x509/pkcs10.cpp | 208 +++++ src/lib/cert/x509/pkcs10.h | 111 +++ src/lib/cert/x509/x509_ca.cpp | 254 ++++++ src/lib/cert/x509/x509_ca.h | 130 +++ src/lib/cert/x509/x509_crl.cpp | 191 +++++ src/lib/cert/x509/x509_crl.h | 111 +++ src/lib/cert/x509/x509_ext.cpp | 660 +++++++++++++++ src/lib/cert/x509/x509_ext.h | 388 +++++++++ src/lib/cert/x509/x509_obj.cpp | 246 ++++++ src/lib/cert/x509/x509_obj.h | 109 +++ src/lib/cert/x509/x509cert.cpp | 587 +++++++++++++ src/lib/cert/x509/x509cert.h | 249 ++++++ src/lib/cert/x509/x509opt.cpp | 107 +++ src/lib/cert/x509/x509path.cpp | 360 ++++++++ src/lib/cert/x509/x509path.h | 165 ++++ src/lib/cert/x509/x509self.cpp | 163 ++++ src/lib/cert/x509/x509self.h | 203 +++++ src/lib/checksum/adler32/adler32.cpp | 81 ++ src/lib/checksum/adler32/adler32.h | 37 + src/lib/checksum/adler32/info.txt | 5 + src/lib/checksum/crc24/crc24.cpp | 102 +++ src/lib/checksum/crc24/crc24.h | 37 + src/lib/checksum/crc24/info.txt | 5 + src/lib/checksum/crc32/crc32.cpp | 102 +++ src/lib/checksum/crc32/crc32.h | 37 + src/lib/checksum/crc32/info.txt | 5 + src/lib/codec/base64/base64.cpp | 245 ++++++ src/lib/codec/base64/base64.h | 127 +++ src/lib/codec/base64/info.txt | 1 + src/lib/codec/hex/hex.cpp | 204 +++++ src/lib/codec/hex/hex.h | 148 ++++ src/lib/codec/hex/info.txt | 1 + src/lib/codec/openpgp/info.txt | 8 + src/lib/codec/openpgp/openpgp.cpp | 196 +++++ src/lib/codec/openpgp/openpgp.h | 61 ++ src/lib/codec/pem/info.txt | 6 + src/lib/codec/pem/pem.cpp | 147 ++++ src/lib/codec/pem/pem.h | 90 ++ src/lib/constructs/aont/info.txt | 8 + src/lib/constructs/aont/package.cpp | 120 +++ src/lib/constructs/aont/package.h | 44 + src/lib/constructs/cryptobox/cryptobox.cpp | 163 ++++ src/lib/constructs/cryptobox/cryptobox.h | 55 ++ src/lib/constructs/cryptobox/info.txt | 13 + src/lib/constructs/cryptobox_psk/cryptobox_psk.cpp | 134 +++ src/lib/constructs/cryptobox_psk/cryptobox_psk.h | 47 ++ src/lib/constructs/cryptobox_psk/info.txt | 10 + src/lib/constructs/fpe_fe1/fpe_fe1.cpp | 193 +++++ src/lib/constructs/fpe_fe1/fpe_fe1.h | 44 + src/lib/constructs/fpe_fe1/info.txt | 7 + src/lib/constructs/rfc3394/info.txt | 1 + src/lib/constructs/rfc3394/rfc3394.cpp | 122 +++ src/lib/constructs/rfc3394/rfc3394.h | 45 + src/lib/constructs/srp6/info.txt | 7 + src/lib/constructs/srp6/srp6.cpp | 163 ++++ src/lib/constructs/srp6/srp6.h | 97 +++ src/lib/constructs/srp6/srp6_files.cpp | 69 ++ src/lib/constructs/srp6/srp6_files.h | 53 ++ src/lib/constructs/tss/info.txt | 8 + src/lib/constructs/tss/tss.cpp | 262 ++++++ src/lib/constructs/tss/tss.h | 76 ++ src/lib/credentials/credentials_manager.cpp | 135 +++ src/lib/credentials/credentials_manager.h | 189 +++++ src/lib/credentials/info.txt | 5 + src/lib/engine/aes_isa_eng/aes_isa_engine.cpp | 36 + src/lib/engine/aes_isa_eng/aes_isa_engine.h | 30 + src/lib/engine/aes_isa_eng/info.txt | 11 + src/lib/engine/asm_engine/asm_engine.cpp | 72 ++ src/lib/engine/asm_engine/asm_engine.h | 32 + src/lib/engine/asm_engine/info.txt | 11 + src/lib/engine/core_engine/core_engine.h | 71 ++ src/lib/engine/core_engine/core_modes.cpp | 279 +++++++ src/lib/engine/core_engine/def_pk_ops.cpp | 170 ++++ src/lib/engine/core_engine/def_powm.cpp | 24 + src/lib/engine/core_engine/info.txt | 24 + src/lib/engine/core_engine/lookup_block.cpp | 298 +++++++ src/lib/engine/core_engine/lookup_hash.cpp | 238 ++++++ src/lib/engine/core_engine/lookup_mac.cpp | 70 ++ src/lib/engine/core_engine/lookup_pbkdf.cpp | 43 + src/lib/engine/core_engine/lookup_stream.cpp | 43 + src/lib/engine/dyn_engine/dyn_engine.cpp | 63 ++ src/lib/engine/dyn_engine/dyn_engine.h | 115 +++ src/lib/engine/dyn_engine/info.txt | 14 + src/lib/engine/engine.cpp | 91 ++ src/lib/engine/engine.h | 150 ++++ src/lib/engine/gnump/gmp_mem.cpp | 83 ++ src/lib/engine/gnump/gmp_powm.cpp | 53 ++ src/lib/engine/gnump/gmp_wrap.cpp | 101 +++ src/lib/engine/gnump/gmp_wrap.h | 41 + src/lib/engine/gnump/gnump_engine.h | 44 + src/lib/engine/gnump/gnump_pk.cpp | 338 ++++++++ src/lib/engine/gnump/info.txt | 23 + src/lib/engine/info.txt | 20 + src/lib/engine/openssl/bn_powm.cpp | 54 ++ src/lib/engine/openssl/bn_wrap.cpp | 116 +++ src/lib/engine/openssl/bn_wrap.h | 60 ++ src/lib/engine/openssl/info.txt | 25 + src/lib/engine/openssl/openssl_engine.h | 49 ++ src/lib/engine/openssl/ossl_arc4.cpp | 89 ++ src/lib/engine/openssl/ossl_bc.cpp | 248 ++++++ src/lib/engine/openssl/ossl_md.cpp | 150 ++++ src/lib/engine/openssl/ossl_pk.cpp | 338 ++++++++ src/lib/engine/simd_engine/info.txt | 15 + src/lib/engine/simd_engine/simd_engine.cpp | 97 +++ src/lib/engine/simd_engine/simd_engine.h | 32 + src/lib/entropy/beos_stats/es_beos.cpp | 63 ++ src/lib/entropy/beos_stats/es_beos.h | 28 + src/lib/entropy/beos_stats/info.txt | 17 + src/lib/entropy/cryptoapi_rng/es_capi.cpp | 93 +++ src/lib/entropy/cryptoapi_rng/es_capi.h | 37 + src/lib/entropy/cryptoapi_rng/info.txt | 20 + src/lib/entropy/dev_random/dev_random.cpp | 97 +++ src/lib/entropy/dev_random/dev_random.h | 37 + src/lib/entropy/dev_random/info.txt | 27 + src/lib/entropy/egd/es_egd.cpp | 156 ++++ src/lib/entropy/egd/es_egd.h | 49 ++ src/lib/entropy/egd/info.txt | 30 + src/lib/entropy/entropy_src.h | 141 ++++ src/lib/entropy/hres_timer/hres_timer.cpp | 117 +++ src/lib/entropy/hres_timer/hres_timer.h | 30 + src/lib/entropy/hres_timer/info.txt | 13 + src/lib/entropy/info.txt | 3 + src/lib/entropy/proc_walk/info.txt | 30 + src/lib/entropy/proc_walk/proc_walk.cpp | 173 ++++ src/lib/entropy/proc_walk/proc_walk.h | 37 + src/lib/entropy/rdrand/info.txt | 22 + src/lib/entropy/rdrand/rdrand.cpp | 60 ++ src/lib/entropy/rdrand/rdrand.h | 28 + src/lib/entropy/unix_procs/info.txt | 25 + src/lib/entropy/unix_procs/unix_proc_sources.cpp | 65 ++ src/lib/entropy/unix_procs/unix_procs.cpp | 258 ++++++ src/lib/entropy/unix_procs/unix_procs.h | 89 ++ src/lib/entropy/win32_stats/es_win32.cpp | 118 +++ src/lib/entropy/win32_stats/es_win32.h | 27 + src/lib/entropy/win32_stats/info.txt | 19 + src/lib/filters/aead_filt/aead_filt.h | 40 + src/lib/filters/aead_filt/info.txt | 5 + src/lib/filters/algo_filt.cpp | 135 +++ src/lib/filters/basefilt.cpp | 70 ++ src/lib/filters/basefilt.h | 120 +++ src/lib/filters/buf_filt.cpp | 103 +++ src/lib/filters/buf_filt.h | 93 +++ src/lib/filters/codec_filt/b64_filt.cpp | 178 ++++ src/lib/filters/codec_filt/b64_filt.h | 88 ++ src/lib/filters/codec_filt/hex_filt.cpp | 172 ++++ src/lib/filters/codec_filt/hex_filt.h | 81 ++ src/lib/filters/codec_filt/info.txt | 5 + src/lib/filters/compression/bzip2/bzip2.cpp | 298 +++++++ src/lib/filters/compression/bzip2/bzip2.h | 65 ++ src/lib/filters/compression/bzip2/info.txt | 11 + src/lib/filters/compression/lzma/info.txt | 11 + src/lib/filters/compression/lzma/lzma.cpp | 327 ++++++++ src/lib/filters/compression/lzma/lzma.h | 74 ++ src/lib/filters/compression/zlib/info.txt | 11 + src/lib/filters/compression/zlib/zlib.cpp | 318 +++++++ src/lib/filters/compression/zlib/zlib.h | 78 ++ src/lib/filters/data_snk.cpp | 63 ++ src/lib/filters/data_snk.h | 67 ++ src/lib/filters/data_src.cpp | 191 +++++ src/lib/filters/data_src.h | 176 ++++ src/lib/filters/fd_unix/fd_unix.cpp | 53 ++ src/lib/filters/fd_unix/fd_unix.h | 33 + src/lib/filters/fd_unix/info.txt | 20 + src/lib/filters/filter.cpp | 127 +++ src/lib/filters/filter.h | 183 ++++ src/lib/filters/filters.h | 213 +++++ src/lib/filters/info.txt | 46 ++ src/lib/filters/key_filt.h | 62 ++ src/lib/filters/out_buf.cpp | 131 +++ src/lib/filters/out_buf.h | 45 + src/lib/filters/pipe.cpp | 302 +++++++ src/lib/filters/pipe.h | 339 ++++++++ src/lib/filters/pipe_io.cpp | 45 + src/lib/filters/pipe_rw.cpp | 171 ++++ src/lib/filters/pk_filts/info.txt | 8 + src/lib/filters/pk_filts/pk_filts.cpp | 115 +++ src/lib/filters/pk_filts/pk_filts.h | 91 ++ src/lib/filters/secqueue.cpp | 228 +++++ src/lib/filters/secqueue.h | 69 ++ src/lib/filters/threaded_fork.cpp | 146 ++++ src/lib/filters/transform_filter.cpp | 100 +++ src/lib/filters/transform_filter.h | 69 ++ src/lib/hash/bmw_512/bmw_512.cpp | 204 +++++ src/lib/hash/bmw_512/bmw_512.h | 38 + src/lib/hash/bmw_512/info.txt | 5 + src/lib/hash/comb4p/comb4p.cpp | 102 +++ src/lib/hash/comb4p/comb4p.h | 61 ++ src/lib/hash/comb4p/info.txt | 1 + src/lib/hash/gost_3411/gost_3411.cpp | 242 ++++++ src/lib/hash/gost_3411/gost_3411.h | 44 + src/lib/hash/gost_3411/info.txt | 5 + src/lib/hash/has160/has160.cpp | 165 ++++ src/lib/hash/has160/has160.h | 39 + src/lib/hash/has160/info.txt | 5 + src/lib/hash/hash.h | 37 + src/lib/hash/info.txt | 3 + src/lib/hash/keccak/info.txt | 5 + src/lib/hash/keccak/keccak.cpp | 198 +++++ src/lib/hash/keccak/keccak.h | 47 ++ src/lib/hash/md2/info.txt | 1 + src/lib/hash/md2/md2.cpp | 113 +++ src/lib/hash/md2/md2.h | 41 + src/lib/hash/md4/info.txt | 5 + src/lib/hash/md4/md4.cpp | 114 +++ src/lib/hash/md4/md4.h | 46 ++ src/lib/hash/md4_x86_32/info.txt | 12 + src/lib/hash/md4_x86_32/md4_x86_32.cpp | 34 + src/lib/hash/md4_x86_32/md4_x86_32.h | 28 + src/lib/hash/md4_x86_32/md4_x86_32_imp.S | 137 +++ src/lib/hash/md5/info.txt | 5 + src/lib/hash/md5/md5.cpp | 136 +++ src/lib/hash/md5/md5.h | 46 ++ src/lib/hash/md5_x86_32/info.txt | 12 + src/lib/hash/md5_x86_32/md5_x86_32.cpp | 31 + src/lib/hash/md5_x86_32/md5_x86_32.h | 28 + src/lib/hash/md5_x86_32/md5_x86_32_imp.S | 166 ++++ src/lib/hash/mdx_hash/info.txt | 3 + src/lib/hash/mdx_hash/mdx_hash.cpp | 108 +++ src/lib/hash/mdx_hash/mdx_hash.h | 68 ++ src/lib/hash/par_hash/info.txt | 1 + src/lib/hash/par_hash/par_hash.cpp | 100 +++ src/lib/hash/par_hash/par_hash.h | 41 + src/lib/hash/rmd128/info.txt | 5 + src/lib/hash/rmd128/rmd128.cpp | 176 ++++ src/lib/hash/rmd128/rmd128.h | 38 + src/lib/hash/rmd160/info.txt | 5 + src/lib/hash/rmd160/rmd160.cpp | 210 +++++ src/lib/hash/rmd160/rmd160.h | 38 + src/lib/hash/sha1/info.txt | 5 + src/lib/hash/sha1/sha160.cpp | 161 ++++ src/lib/hash/sha1/sha160.h | 60 ++ src/lib/hash/sha1_sse2/info.txt | 8 + src/lib/hash/sha1_sse2/sha1_sse2.cpp | 335 ++++++++ src/lib/hash/sha1_sse2/sha1_sse2.h | 29 + src/lib/hash/sha1_x86_32/info.txt | 12 + src/lib/hash/sha1_x86_32/sha1_x86_32.cpp | 31 + src/lib/hash/sha1_x86_32/sha1_x86_32.h | 31 + src/lib/hash/sha1_x86_32/sha1_x86_32_imp.S | 244 ++++++ src/lib/hash/sha1_x86_64/info.txt | 13 + src/lib/hash/sha1_x86_64/sha1_x86_64.cpp | 31 + src/lib/hash/sha1_x86_64/sha1_x86_64.h | 28 + src/lib/hash/sha1_x86_64/sha1_x86_64_imp.S | 266 ++++++ src/lib/hash/sha2_32/info.txt | 5 + src/lib/hash/sha2_32/sha2_32.cpp | 227 +++++ src/lib/hash/sha2_32/sha2_32.h | 60 ++ src/lib/hash/sha2_64/info.txt | 5 + src/lib/hash/sha2_64/sha2_64.cpp | 242 ++++++ src/lib/hash/sha2_64/sha2_64.h | 59 ++ src/lib/hash/skein/info.txt | 5 + src/lib/hash/skein/skein_512.cpp | 274 ++++++ src/lib/hash/skein/skein_512.h | 52 ++ src/lib/hash/tiger/info.txt | 5 + src/lib/hash/tiger/tig_tab.cpp | 364 ++++++++ src/lib/hash/tiger/tiger.cpp | 187 +++++ src/lib/hash/tiger/tiger.h | 55 ++ src/lib/hash/whirlpool/info.txt | 5 + src/lib/hash/whirlpool/whrl_tab.cpp | 540 ++++++++++++ src/lib/hash/whirlpool/whrlpool.cpp | 146 ++++ src/lib/hash/whirlpool/whrlpool.h | 47 ++ src/lib/kdf/info.txt | 5 + src/lib/kdf/kdf.cpp | 81 ++ src/lib/kdf/kdf.h | 136 +++ src/lib/kdf/kdf1/info.txt | 5 + src/lib/kdf/kdf1/kdf1.cpp | 24 + src/lib/kdf/kdf1/kdf1.h | 39 + src/lib/kdf/kdf2/info.txt | 5 + src/lib/kdf/kdf2/kdf2.cpp | 40 + src/lib/kdf/kdf2/kdf2.h | 37 + src/lib/kdf/mgf1/info.txt | 5 + src/lib/kdf/mgf1/mgf1.cpp | 56 ++ src/lib/kdf/mgf1/mgf1.h | 36 + src/lib/kdf/prf_ssl3/info.txt | 7 + src/lib/kdf/prf_ssl3/prf_ssl3.cpp | 76 ++ src/lib/kdf/prf_ssl3/prf_ssl3.h | 30 + src/lib/kdf/prf_tls/info.txt | 8 + src/lib/kdf/prf_tls/prf_tls.cpp | 117 +++ src/lib/kdf/prf_tls/prf_tls.h | 58 ++ src/lib/kdf/prf_x942/info.txt | 7 + src/lib/kdf/prf_x942/prf_x942.cpp | 92 +++ src/lib/kdf/prf_x942/prf_x942.h | 34 + src/lib/libstate/botan.h | 23 + src/lib/libstate/global_rng.cpp | 123 +++ src/lib/libstate/global_state.cpp | 91 ++ src/lib/libstate/global_state.h | 69 ++ src/lib/libstate/info.txt | 21 + src/lib/libstate/init.cpp | 47 ++ src/lib/libstate/init.h | 48 ++ src/lib/libstate/libstate.cpp | 104 +++ src/lib/libstate/libstate.h | 60 ++ src/lib/libstate/lookup.cpp | 124 +++ src/lib/libstate/lookup.h | 276 +++++++ src/lib/mac/cbc_mac/cbc_mac.cpp | 105 +++ src/lib/mac/cbc_mac/cbc_mac.h | 49 ++ src/lib/mac/cbc_mac/info.txt | 5 + src/lib/mac/cmac/cmac.cpp | 156 ++++ src/lib/mac/cmac/cmac.h | 63 ++ src/lib/mac/cmac/info.txt | 5 + src/lib/mac/hmac/hmac.cpp | 97 +++ src/lib/mac/hmac/hmac.h | 53 ++ src/lib/mac/hmac/info.txt | 5 + src/lib/mac/info.txt | 3 + src/lib/mac/mac.cpp | 26 + src/lib/mac/mac.h | 46 ++ src/lib/mac/ssl3mac/info.txt | 5 + src/lib/mac/ssl3mac/ssl3_mac.cpp | 90 ++ src/lib/mac/ssl3mac/ssl3_mac.h | 49 ++ src/lib/mac/x919_mac/info.txt | 5 + src/lib/mac/x919_mac/x919_mac.cpp | 103 +++ src/lib/mac/x919_mac/x919_mac.h | 54 ++ src/lib/math/bigint/big_code.cpp | 150 ++++ src/lib/math/bigint/big_io.cpp | 55 ++ src/lib/math/bigint/big_ops2.cpp | 221 +++++ src/lib/math/bigint/big_ops3.cpp | 191 +++++ src/lib/math/bigint/big_rand.cpp | 48 ++ src/lib/math/bigint/bigint.cpp | 350 ++++++++ src/lib/math/bigint/bigint.h | 570 +++++++++++++ src/lib/math/bigint/divide.cpp | 140 ++++ src/lib/math/bigint/divide.h | 29 + src/lib/math/bigint/info.txt | 25 + src/lib/math/ec_gfp/curve_gfp.h | 161 ++++ src/lib/math/ec_gfp/info.txt | 16 + src/lib/math/ec_gfp/point_gfp.cpp | 606 ++++++++++++++ src/lib/math/ec_gfp/point_gfp.h | 300 +++++++ src/lib/math/mp/info.txt | 23 + src/lib/math/mp/mp_asm.cpp | 184 +++++ src/lib/math/mp/mp_comba.cpp | 920 +++++++++++++++++++++ src/lib/math/mp/mp_core.h | 175 ++++ src/lib/math/mp/mp_generic/info.txt | 6 + src/lib/math/mp/mp_generic/mp_asmi.h | 207 +++++ src/lib/math/mp/mp_generic/mp_madd.h | 73 ++ src/lib/math/mp/mp_karat.cpp | 303 +++++++ src/lib/math/mp/mp_misc.cpp | 79 ++ src/lib/math/mp/mp_monty.cpp | 101 +++ src/lib/math/mp/mp_mulop.cpp | 77 ++ src/lib/math/mp/mp_shift.cpp | 138 ++++ src/lib/math/mp/mp_types.h | 46 ++ src/lib/math/mp/mp_x86_32/info.txt | 18 + src/lib/math/mp/mp_x86_32/mp_asmi.h | 240 ++++++ src/lib/math/mp/mp_x86_32/mp_madd.h | 67 ++ src/lib/math/mp/mp_x86_32_msvc/info.txt | 16 + src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h | 542 ++++++++++++ src/lib/math/mp/mp_x86_64/info.txt | 18 + src/lib/math/mp/mp_x86_64/mp_asmi.h | 248 ++++++ src/lib/math/mp/mp_x86_64/mp_madd.h | 69 ++ src/lib/math/numbertheory/def_powm.h | 63 ++ src/lib/math/numbertheory/dsa_gen.cpp | 134 +++ src/lib/math/numbertheory/info.txt | 35 + src/lib/math/numbertheory/jacobi.cpp | 53 ++ src/lib/math/numbertheory/make_prm.cpp | 100 +++ src/lib/math/numbertheory/mp_numth.cpp | 74 ++ src/lib/math/numbertheory/numthry.cpp | 409 +++++++++ src/lib/math/numbertheory/numthry.h | 237 ++++++ src/lib/math/numbertheory/pow_mod.cpp | 211 +++++ src/lib/math/numbertheory/pow_mod.h | 104 +++ src/lib/math/numbertheory/powm_fw.cpp | 69 ++ src/lib/math/numbertheory/powm_mnt.cpp | 142 ++++ src/lib/math/numbertheory/primes.cpp | 609 ++++++++++++++ src/lib/math/numbertheory/reducer.cpp | 81 ++ src/lib/math/numbertheory/reducer.h | 61 ++ src/lib/math/numbertheory/ressol.cpp | 81 ++ src/lib/modes/aead/aead.cpp | 122 +++ src/lib/modes/aead/aead.h | 66 ++ src/lib/modes/aead/ccm/ccm.cpp | 266 ++++++ src/lib/modes/aead/ccm/ccm.h | 128 +++ src/lib/modes/aead/ccm/info.txt | 1 + src/lib/modes/aead/eax/eax.cpp | 170 ++++ src/lib/modes/aead/eax/eax.h | 114 +++ src/lib/modes/aead/eax/info.txt | 7 + src/lib/modes/aead/gcm/clmul/clmul.cpp | 76 ++ src/lib/modes/aead/gcm/clmul/clmul.h | 14 + src/lib/modes/aead/gcm/clmul/info.txt | 8 + src/lib/modes/aead/gcm/gcm.cpp | 290 +++++++ src/lib/modes/aead/gcm/gcm.h | 150 ++++ src/lib/modes/aead/gcm/info.txt | 6 + src/lib/modes/aead/info.txt | 1 + src/lib/modes/aead/ocb/info.txt | 6 + src/lib/modes/aead/ocb/ocb.cpp | 432 ++++++++++ src/lib/modes/aead/ocb/ocb.h | 124 +++ src/lib/modes/aead/siv/info.txt | 3 + src/lib/modes/aead/siv/siv.cpp | 180 ++++ src/lib/modes/aead/siv/siv.h | 114 +++ src/lib/modes/cbc/cbc.cpp | 299 +++++++ src/lib/modes/cbc/cbc.h | 132 +++ src/lib/modes/cbc/info.txt | 5 + src/lib/modes/cfb/cfb.cpp | 150 ++++ src/lib/modes/cfb/cfb.h | 91 ++ src/lib/modes/cfb/info.txt | 1 + src/lib/modes/cipher_mode.h | 30 + src/lib/modes/ecb/ecb.cpp | 149 ++++ src/lib/modes/ecb/ecb.h | 89 ++ src/lib/modes/ecb/info.txt | 5 + src/lib/modes/info.txt | 4 + src/lib/modes/mode_pad/info.txt | 1 + src/lib/modes/mode_pad/mode_pad.cpp | 103 +++ src/lib/modes/mode_pad/mode_pad.h | 124 +++ src/lib/modes/xts/info.txt | 1 + src/lib/modes/xts/xts.cpp | 285 +++++++ src/lib/modes/xts/xts.h | 86 ++ src/lib/passhash/bcrypt/bcrypt.cpp | 150 ++++ src/lib/passhash/bcrypt/bcrypt.h | 37 + src/lib/passhash/bcrypt/info.txt | 9 + src/lib/passhash/passhash9/info.txt | 9 + src/lib/passhash/passhash9/passhash9.cpp | 149 ++++ src/lib/passhash/passhash9/passhash9.h | 43 + src/lib/pbe/get_pbe.cpp | 140 ++++ src/lib/pbe/get_pbe.h | 44 + src/lib/pbe/info.txt | 7 + src/lib/pbe/pbe.h | 39 + src/lib/pbe/pbes1/info.txt | 10 + src/lib/pbe/pbes1/pbes1.cpp | 193 +++++ src/lib/pbe/pbes1/pbes1.h | 69 ++ src/lib/pbe/pbes2/info.txt | 14 + src/lib/pbe/pbes2/pbes2.cpp | 209 +++++ src/lib/pbe/pbes2/pbes2.h | 70 ++ src/lib/pbkdf/info.txt | 3 + src/lib/pbkdf/pbkdf.cpp | 44 + src/lib/pbkdf/pbkdf.h | 124 +++ src/lib/pbkdf/pbkdf1/info.txt | 5 + src/lib/pbkdf/pbkdf1/pbkdf1.cpp | 58 ++ src/lib/pbkdf/pbkdf1/pbkdf1.h | 61 ++ src/lib/pbkdf/pbkdf2/info.txt | 5 + src/lib/pbkdf/pbkdf2/pbkdf2.cpp | 111 +++ src/lib/pbkdf/pbkdf2/pbkdf2.h | 55 ++ src/lib/pk_pad/eme.cpp | 50 ++ src/lib/pk_pad/eme.h | 109 +++ src/lib/pk_pad/eme1/eme1.cpp | 130 +++ src/lib/pk_pad/eme1/eme1.h | 43 + src/lib/pk_pad/eme1/info.txt | 9 + src/lib/pk_pad/eme_pkcs/eme_pkcs.cpp | 70 ++ src/lib/pk_pad/eme_pkcs/eme_pkcs.h | 30 + src/lib/pk_pad/eme_pkcs/info.txt | 1 + src/lib/pk_pad/emsa.h | 68 ++ src/lib/pk_pad/emsa1/emsa1.cpp | 105 +++ src/lib/pk_pad/emsa1/emsa1.h | 48 ++ src/lib/pk_pad/emsa1/info.txt | 5 + src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp | 29 + src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h | 35 + src/lib/pk_pad/emsa1_bsi/info.txt | 5 + src/lib/pk_pad/emsa2/emsa2.cpp | 112 +++ src/lib/pk_pad/emsa2/emsa2.h | 45 + src/lib/pk_pad/emsa2/info.txt | 6 + src/lib/pk_pad/emsa3/emsa3.cpp | 152 ++++ src/lib/pk_pad/emsa3/emsa3.h | 68 ++ src/lib/pk_pad/emsa3/info.txt | 6 + src/lib/pk_pad/emsa4/emsa4.cpp | 146 ++++ src/lib/pk_pad/emsa4/emsa4.h | 51 ++ src/lib/pk_pad/emsa4/info.txt | 7 + src/lib/pk_pad/emsa_raw/emsa_raw.cpp | 68 ++ src/lib/pk_pad/emsa_raw/emsa_raw.h | 35 + src/lib/pk_pad/emsa_raw/info.txt | 1 + src/lib/pk_pad/get_pk_pad.cpp | 139 ++++ src/lib/pk_pad/hash_id/hash_id.cpp | 129 +++ src/lib/pk_pad/hash_id/hash_id.h | 34 + src/lib/pk_pad/hash_id/info.txt | 5 + src/lib/pk_pad/info.txt | 8 + src/lib/prf/hkdf/hkdf.cpp | 62 ++ src/lib/prf/hkdf/hkdf.h | 51 ++ src/lib/prf/hkdf/info.txt | 1 + src/lib/pubkey/blinding.cpp | 49 ++ src/lib/pubkey/blinding.h | 46 ++ src/lib/pubkey/dh/dh.cpp | 98 +++ src/lib/pubkey/dh/dh.h | 94 +++ src/lib/pubkey/dh/info.txt | 16 + src/lib/pubkey/dl_algo/dl_algo.cpp | 91 ++ src/lib/pubkey/dl_algo/dl_algo.h | 116 +++ src/lib/pubkey/dl_algo/info.txt | 8 + src/lib/pubkey/dl_group/dl_group.cpp | 337 ++++++++ src/lib/pubkey/dl_group/dl_group.h | 170 ++++ src/lib/pubkey/dl_group/info.txt | 10 + src/lib/pubkey/dl_group/named.cpp | 360 ++++++++ src/lib/pubkey/dlies/dlies.cpp | 146 ++++ src/lib/pubkey/dlies/dlies.h | 71 ++ src/lib/pubkey/dlies/info.txt | 7 + src/lib/pubkey/dsa/dsa.cpp | 143 ++++ src/lib/pubkey/dsa/dsa.h | 107 +++ src/lib/pubkey/dsa/info.txt | 9 + src/lib/pubkey/ec_group/ec_group.cpp | 134 +++ src/lib/pubkey/ec_group/ec_group.h | 148 ++++ src/lib/pubkey/ec_group/info.txt | 10 + src/lib/pubkey/ec_group/named.cpp | 307 +++++++ src/lib/pubkey/ecc_key/ecc_key.cpp | 148 ++++ src/lib/pubkey/ecc_key/ecc_key.h | 121 +++ src/lib/pubkey/ecc_key/info.txt | 10 + src/lib/pubkey/ecdh/ecdh.cpp | 35 + src/lib/pubkey/ecdh/ecdh.h | 107 +++ src/lib/pubkey/ecdh/info.txt | 10 + src/lib/pubkey/ecdsa/ecdsa.cpp | 97 +++ src/lib/pubkey/ecdsa/ecdsa.h | 138 ++++ src/lib/pubkey/ecdsa/info.txt | 9 + src/lib/pubkey/elgamal/elgamal.cpp | 135 +++ src/lib/pubkey/elgamal/elgamal.h | 96 +++ src/lib/pubkey/elgamal/info.txt | 9 + src/lib/pubkey/gost_3410/gost_3410.cpp | 176 ++++ src/lib/pubkey/gost_3410/gost_3410.h | 139 ++++ src/lib/pubkey/gost_3410/info.txt | 13 + src/lib/pubkey/if_algo/if_algo.cpp | 143 ++++ src/lib/pubkey/if_algo/if_algo.h | 108 +++ src/lib/pubkey/if_algo/info.txt | 10 + src/lib/pubkey/info.txt | 41 + src/lib/pubkey/keypair/info.txt | 5 + src/lib/pubkey/keypair/keypair.cpp | 81 ++ src/lib/pubkey/keypair/keypair.h | 47 ++ src/lib/pubkey/nr/info.txt | 9 + src/lib/pubkey/nr/nr.cpp | 143 ++++ src/lib/pubkey/nr/nr.h | 104 +++ src/lib/pubkey/pk_algs.cpp | 160 ++++ src/lib/pubkey/pk_algs.h | 24 + src/lib/pubkey/pk_keys.cpp | 55 ++ src/lib/pubkey/pk_keys.h | 149 ++++ src/lib/pubkey/pk_ops.h | 163 ++++ src/lib/pubkey/pkcs8.cpp | 284 +++++++ src/lib/pubkey/pkcs8.h | 141 ++++ src/lib/pubkey/pubkey.cpp | 386 +++++++++ src/lib/pubkey/pubkey.h | 461 +++++++++++ src/lib/pubkey/rsa/info.txt | 8 + src/lib/pubkey/rsa/rsa.cpp | 121 +++ src/lib/pubkey/rsa/rsa.h | 155 ++++ src/lib/pubkey/rw/info.txt | 8 + src/lib/pubkey/rw/rw.cpp | 130 +++ src/lib/pubkey/rw/rw.h | 107 +++ src/lib/pubkey/workfactor.cpp | 50 ++ src/lib/pubkey/workfactor.h | 24 + src/lib/pubkey/x509_key.cpp | 111 +++ src/lib/pubkey/x509_key.h | 74 ++ src/lib/rng/auto_rng/auto_rng.h | 41 + src/lib/rng/auto_rng/info.txt | 8 + src/lib/rng/hmac_rng/hmac_rng.cpp | 205 +++++ src/lib/rng/hmac_rng/hmac_rng.h | 57 ++ src/lib/rng/hmac_rng/info.txt | 5 + src/lib/rng/info.txt | 3 + src/lib/rng/rng.cpp | 34 + src/lib/rng/rng.h | 174 ++++ src/lib/rng/x931_rng/info.txt | 5 + src/lib/rng/x931_rng/x931_rng.cpp | 146 ++++ src/lib/rng/x931_rng/x931_rng.h | 50 ++ src/lib/selftest/info.txt | 8 + src/lib/selftest/selftest.cpp | 342 ++++++++ src/lib/selftest/selftest.h | 60 ++ src/lib/simd/info.txt | 9 + src/lib/simd/simd_32.h | 30 + src/lib/simd/simd_altivec/info.txt | 9 + src/lib/simd/simd_altivec/simd_altivec.h | 218 +++++ src/lib/simd/simd_scalar/info.txt | 7 + src/lib/simd/simd_scalar/simd_scalar.h | 215 +++++ src/lib/simd/simd_sse2/info.txt | 9 + src/lib/simd/simd_sse2/simd_sse2.h | 169 ++++ src/lib/stream/ctr/ctr.cpp | 134 +++ src/lib/stream/ctr/ctr.h | 61 ++ src/lib/stream/ctr/info.txt | 6 + src/lib/stream/info.txt | 5 + src/lib/stream/ofb/info.txt | 6 + src/lib/stream/ofb/ofb.cpp | 93 +++ src/lib/stream/ofb/ofb.h | 56 ++ src/lib/stream/rc4/info.txt | 1 + src/lib/stream/rc4/rc4.cpp | 109 +++ src/lib/stream/rc4/rc4.h | 55 ++ src/lib/stream/salsa20/info.txt | 1 + src/lib/stream/salsa20/salsa20.cpp | 243 ++++++ src/lib/stream/salsa20/salsa20.h | 46 ++ src/lib/stream/stream_cipher.cpp | 24 + src/lib/stream/stream_cipher.h | 70 ++ src/lib/tls/info.txt | 90 ++ src/lib/tls/msg_cert_req.cpp | 163 ++++ src/lib/tls/msg_cert_verify.cpp | 117 +++ src/lib/tls/msg_certificate.cpp | 88 ++ src/lib/tls/msg_client_hello.cpp | 287 +++++++ src/lib/tls/msg_client_kex.cpp | 419 ++++++++++ src/lib/tls/msg_finished.cpp | 104 +++ src/lib/tls/msg_hello_verify.cpp | 69 ++ src/lib/tls/msg_next_protocol.cpp | 55 ++ src/lib/tls/msg_server_hello.cpp | 142 ++++ src/lib/tls/msg_server_kex.cpp | 285 +++++++ src/lib/tls/msg_session_ticket.cpp | 57 ++ src/lib/tls/sessions_sqlite/info.txt | 6 + .../sessions_sqlite/tls_session_manager_sqlite.cpp | 223 +++++ .../sessions_sqlite/tls_session_manager_sqlite.h | 80 ++ src/lib/tls/tls_alert.cpp | 123 +++ src/lib/tls/tls_alert.h | 113 +++ src/lib/tls/tls_blocking.cpp | 90 ++ src/lib/tls/tls_blocking.h | 97 +++ src/lib/tls/tls_channel.cpp | 668 +++++++++++++++ src/lib/tls/tls_channel.h | 259 ++++++ src/lib/tls/tls_ciphersuite.cpp | 236 ++++++ src/lib/tls/tls_ciphersuite.h | 137 +++ src/lib/tls/tls_client.cpp | 530 ++++++++++++ src/lib/tls/tls_client.h | 106 +++ src/lib/tls/tls_exceptn.h | 47 ++ src/lib/tls/tls_extensions.cpp | 533 ++++++++++++ src/lib/tls/tls_extensions.h | 397 +++++++++ src/lib/tls/tls_handshake_hash.cpp | 86 ++ src/lib/tls/tls_handshake_hash.h | 50 ++ src/lib/tls/tls_handshake_io.cpp | 381 +++++++++ src/lib/tls/tls_handshake_io.h | 168 ++++ src/lib/tls/tls_handshake_msg.h | 36 + src/lib/tls/tls_handshake_state.cpp | 442 ++++++++++ src/lib/tls/tls_handshake_state.h | 210 +++++ src/lib/tls/tls_heartbeats.cpp | 78 ++ src/lib/tls/tls_heartbeats.h | 43 + src/lib/tls/tls_magic.h | 72 ++ src/lib/tls/tls_messages.h | 567 +++++++++++++ src/lib/tls/tls_policy.cpp | 286 +++++++ src/lib/tls/tls_policy.h | 194 +++++ src/lib/tls/tls_reader.h | 226 +++++ src/lib/tls/tls_record.cpp | 622 ++++++++++++++ src/lib/tls/tls_record.h | 135 +++ src/lib/tls/tls_seq_numbers.h | 125 +++ src/lib/tls/tls_server.cpp | 725 ++++++++++++++++ src/lib/tls/tls_server.h | 71 ++ src/lib/tls/tls_server_info.h | 91 ++ src/lib/tls/tls_session.cpp | 177 ++++ src/lib/tls/tls_session.h | 206 +++++ src/lib/tls/tls_session_key.cpp | 86 ++ src/lib/tls/tls_session_key.h | 50 ++ src/lib/tls/tls_session_manager.h | 149 ++++ src/lib/tls/tls_session_manager_memory.cpp | 122 +++ src/lib/tls/tls_suite_info.cpp | 463 +++++++++++ src/lib/tls/tls_version.cpp | 101 +++ src/lib/tls/tls_version.h | 151 ++++ src/lib/utils/asm_x86_32/asm_x86_32.h | 128 +++ src/lib/utils/asm_x86_32/info.txt | 29 + src/lib/utils/asm_x86_64/asm_x86_64.h | 127 +++ src/lib/utils/asm_x86_64/info.txt | 27 + src/lib/utils/assert.cpp | 36 + src/lib/utils/assert.h | 83 ++ src/lib/utils/bit_ops.h | 103 +++ src/lib/utils/boost/info.txt | 7 + src/lib/utils/bswap.h | 142 ++++ src/lib/utils/calendar.cpp | 52 ++ src/lib/utils/calendar.h | 63 ++ src/lib/utils/charset.cpp | 201 +++++ src/lib/utils/charset.h | 46 ++ src/lib/utils/cpuid.cpp | 236 ++++++ src/lib/utils/cpuid.h | 153 ++++ src/lib/utils/datastor/datastor.cpp | 165 ++++ src/lib/utils/datastor/datastor.h | 57 ++ src/lib/utils/datastor/info.txt | 3 + src/lib/utils/dyn_load/dyn_load.cpp | 79 ++ src/lib/utils/dyn_load/dyn_load.h | 67 ++ src/lib/utils/dyn_load/info.txt | 24 + src/lib/utils/exceptn.h | 181 ++++ src/lib/utils/get_byte.h | 30 + src/lib/utils/http_util/http_util.cpp | 220 +++++ src/lib/utils/http_util/http_util.h | 97 +++ src/lib/utils/http_util/info.txt | 1 + src/lib/utils/info.txt | 29 + src/lib/utils/loadstor.h | 627 ++++++++++++++ src/lib/utils/mem_ops.h | 75 ++ src/lib/utils/mul128.h | 121 +++ src/lib/utils/parsing.cpp | 302 +++++++ src/lib/utils/parsing.h | 133 +++ src/lib/utils/prefetch.h | 39 + src/lib/utils/read_cfg.cpp | 115 +++ src/lib/utils/rotate.h | 43 + src/lib/utils/rounding.h | 61 ++ src/lib/utils/semaphore.cpp | 39 + src/lib/utils/semaphore.h | 34 + src/lib/utils/sqlite3/info.txt | 14 + src/lib/utils/sqlite3/sqlite3.cpp | 137 +++ src/lib/utils/sqlite3/sqlite3.h | 68 ++ src/lib/utils/stl_util.h | 94 +++ src/lib/utils/types.h | 48 ++ src/lib/utils/version.cpp | 55 ++ src/lib/utils/version.h | 72 ++ src/lib/utils/xor_buf.h | 113 +++ src/lib/utils/zero_mem.cpp | 20 + 860 files changed, 95009 insertions(+) create mode 100644 src/lib/algo_base/algo_base.h create mode 100644 src/lib/algo_base/buf_comp.h create mode 100644 src/lib/algo_base/info.txt create mode 100644 src/lib/algo_base/key_spec.h create mode 100644 src/lib/algo_base/scan_name.cpp create mode 100644 src/lib/algo_base/scan_name.h create mode 100644 src/lib/algo_base/sym_algo.h create mode 100644 src/lib/algo_base/symkey.cpp create mode 100644 src/lib/algo_base/symkey.h create mode 100644 src/lib/algo_base/transform.h create mode 100644 src/lib/algo_factory/algo_cache.h create mode 100644 src/lib/algo_factory/algo_factory.cpp create mode 100644 src/lib/algo_factory/algo_factory.h create mode 100644 src/lib/algo_factory/info.txt create mode 100644 src/lib/algo_factory/prov_weight.cpp create mode 100644 src/lib/alloc/info.txt create mode 100644 src/lib/alloc/locking_allocator/info.txt create mode 100644 src/lib/alloc/locking_allocator/locking_allocator.cpp create mode 100644 src/lib/alloc/locking_allocator/locking_allocator.h create mode 100644 src/lib/alloc/secmem.h create mode 100644 src/lib/asn1/alg_id.cpp create mode 100644 src/lib/asn1/alg_id.h create mode 100644 src/lib/asn1/asn1_alt_name.cpp create mode 100644 src/lib/asn1/asn1_alt_name.h create mode 100644 src/lib/asn1/asn1_attribute.cpp create mode 100644 src/lib/asn1/asn1_attribute.h create mode 100644 src/lib/asn1/asn1_obj.cpp create mode 100644 src/lib/asn1/asn1_obj.h create mode 100644 src/lib/asn1/asn1_oid.cpp create mode 100644 src/lib/asn1/asn1_oid.h create mode 100644 src/lib/asn1/asn1_str.cpp create mode 100644 src/lib/asn1/asn1_str.h create mode 100644 src/lib/asn1/asn1_time.cpp create mode 100644 src/lib/asn1/asn1_time.h create mode 100644 src/lib/asn1/ber_dec.cpp create mode 100644 src/lib/asn1/ber_dec.h create mode 100644 src/lib/asn1/der_enc.cpp create mode 100644 src/lib/asn1/der_enc.h create mode 100644 src/lib/asn1/info.txt create mode 100644 src/lib/asn1/oid_lookup/default.cpp create mode 100644 src/lib/asn1/oid_lookup/info.txt create mode 100644 src/lib/asn1/oid_lookup/oids.cpp create mode 100644 src/lib/asn1/oid_lookup/oids.h create mode 100644 src/lib/asn1/x509_dn.cpp create mode 100644 src/lib/asn1/x509_dn.h create mode 100644 src/lib/benchmark/benchmark.cpp create mode 100644 src/lib/benchmark/benchmark.h create mode 100644 src/lib/benchmark/info.txt create mode 100644 src/lib/block/aes/aes.cpp create mode 100644 src/lib/block/aes/aes.h create mode 100644 src/lib/block/aes/info.txt create mode 100644 src/lib/block/aes_ni/aes_ni.cpp create mode 100644 src/lib/block/aes_ni/aes_ni.h create mode 100644 src/lib/block/aes_ni/info.txt create mode 100644 src/lib/block/aes_ssse3/aes_ssse3.cpp create mode 100644 src/lib/block/aes_ssse3/aes_ssse3.h create mode 100644 src/lib/block/aes_ssse3/info.txt create mode 100644 src/lib/block/block_cipher.h create mode 100644 src/lib/block/blowfish/blfs_tab.cpp create mode 100644 src/lib/block/blowfish/blowfish.cpp create mode 100644 src/lib/block/blowfish/blowfish.h create mode 100644 src/lib/block/blowfish/info.txt create mode 100644 src/lib/block/camellia/camellia.cpp create mode 100644 src/lib/block/camellia/camellia.h create mode 100644 src/lib/block/camellia/camellia_sbox.h create mode 100644 src/lib/block/camellia/info.txt create mode 100644 src/lib/block/cascade/cascade.cpp create mode 100644 src/lib/block/cascade/cascade.h create mode 100644 src/lib/block/cascade/info.txt create mode 100644 src/lib/block/cast/cast128.cpp create mode 100644 src/lib/block/cast/cast128.h create mode 100644 src/lib/block/cast/cast256.cpp create mode 100644 src/lib/block/cast/cast256.h create mode 100644 src/lib/block/cast/cast_sboxes.h create mode 100644 src/lib/block/cast/info.txt create mode 100644 src/lib/block/des/des.cpp create mode 100644 src/lib/block/des/des.h create mode 100644 src/lib/block/des/des_tab.cpp create mode 100644 src/lib/block/des/desx.cpp create mode 100644 src/lib/block/des/desx.h create mode 100644 src/lib/block/des/info.txt create mode 100644 src/lib/block/gost_28147/gost_28147.cpp create mode 100644 src/lib/block/gost_28147/gost_28147.h create mode 100644 src/lib/block/gost_28147/info.txt create mode 100644 src/lib/block/idea/idea.cpp create mode 100644 src/lib/block/idea/idea.h create mode 100644 src/lib/block/idea/info.txt create mode 100644 src/lib/block/idea_sse2/idea_sse2.cpp create mode 100644 src/lib/block/idea_sse2/idea_sse2.h create mode 100644 src/lib/block/idea_sse2/info.txt create mode 100644 src/lib/block/info.txt create mode 100644 src/lib/block/kasumi/info.txt create mode 100644 src/lib/block/kasumi/kasumi.cpp create mode 100644 src/lib/block/kasumi/kasumi.h create mode 100644 src/lib/block/lion/info.txt create mode 100644 src/lib/block/lion/lion.cpp create mode 100644 src/lib/block/lion/lion.h create mode 100644 src/lib/block/lubyrack/info.txt create mode 100644 src/lib/block/lubyrack/lubyrack.cpp create mode 100644 src/lib/block/lubyrack/lubyrack.h create mode 100644 src/lib/block/mars/info.txt create mode 100644 src/lib/block/mars/mars.cpp create mode 100644 src/lib/block/mars/mars.h create mode 100644 src/lib/block/misty1/info.txt create mode 100644 src/lib/block/misty1/misty1.cpp create mode 100644 src/lib/block/misty1/misty1.h create mode 100644 src/lib/block/noekeon/info.txt create mode 100644 src/lib/block/noekeon/noekeon.cpp create mode 100644 src/lib/block/noekeon/noekeon.h create mode 100644 src/lib/block/noekeon_simd/info.txt create mode 100644 src/lib/block/noekeon_simd/noekeon_simd.cpp create mode 100644 src/lib/block/noekeon_simd/noekeon_simd.h create mode 100644 src/lib/block/rc2/info.txt create mode 100644 src/lib/block/rc2/rc2.cpp create mode 100644 src/lib/block/rc2/rc2.h create mode 100644 src/lib/block/rc5/info.txt create mode 100644 src/lib/block/rc5/rc5.cpp create mode 100644 src/lib/block/rc5/rc5.h create mode 100644 src/lib/block/rc6/info.txt create mode 100644 src/lib/block/rc6/rc6.cpp create mode 100644 src/lib/block/rc6/rc6.h create mode 100644 src/lib/block/safer/info.txt create mode 100644 src/lib/block/safer/safer_sk.cpp create mode 100644 src/lib/block/safer/safer_sk.h create mode 100644 src/lib/block/seed/info.txt create mode 100644 src/lib/block/seed/seed.cpp create mode 100644 src/lib/block/seed/seed.h create mode 100644 src/lib/block/seed/seed_tab.cpp create mode 100644 src/lib/block/serpent/info.txt create mode 100644 src/lib/block/serpent/serpent.cpp create mode 100644 src/lib/block/serpent/serpent.h create mode 100644 src/lib/block/serpent/serpent_sbox.h create mode 100644 src/lib/block/serpent_simd/info.txt create mode 100644 src/lib/block/serpent_simd/serp_simd.cpp create mode 100644 src/lib/block/serpent_simd/serp_simd.h create mode 100644 src/lib/block/serpent_x86_32/info.txt create mode 100644 src/lib/block/serpent_x86_32/serp_x86_32.cpp create mode 100644 src/lib/block/serpent_x86_32/serp_x86_32.h create mode 100644 src/lib/block/serpent_x86_32/serp_x86_32_imp.S create mode 100644 src/lib/block/skipjack/info.txt create mode 100644 src/lib/block/skipjack/skipjack.cpp create mode 100644 src/lib/block/skipjack/skipjack.h create mode 100644 src/lib/block/square/info.txt create mode 100644 src/lib/block/square/sqr_tab.cpp create mode 100644 src/lib/block/square/square.cpp create mode 100644 src/lib/block/square/square.h create mode 100644 src/lib/block/tea/info.txt create mode 100644 src/lib/block/tea/tea.cpp create mode 100644 src/lib/block/tea/tea.h create mode 100644 src/lib/block/threefish/info.txt create mode 100644 src/lib/block/threefish/threefish.cpp create mode 100644 src/lib/block/threefish/threefish.h create mode 100644 src/lib/block/threefish_avx2/info.txt create mode 100644 src/lib/block/threefish_avx2/threefish_avx2.cpp create mode 100644 src/lib/block/threefish_avx2/threefish_avx2.h create mode 100644 src/lib/block/twofish/info.txt create mode 100644 src/lib/block/twofish/two_tab.cpp create mode 100644 src/lib/block/twofish/twofish.cpp create mode 100644 src/lib/block/twofish/twofish.h create mode 100644 src/lib/block/xtea/info.txt create mode 100644 src/lib/block/xtea/xtea.cpp create mode 100644 src/lib/block/xtea/xtea.h create mode 100644 src/lib/block/xtea_simd/info.txt create mode 100644 src/lib/block/xtea_simd/xtea_simd.cpp create mode 100644 src/lib/block/xtea_simd/xtea_simd.h create mode 100644 src/lib/cert/cvc/asn1_eac_str.cpp create mode 100644 src/lib/cert/cvc/asn1_eac_tm.cpp create mode 100644 src/lib/cert/cvc/cvc_ado.cpp create mode 100644 src/lib/cert/cvc/cvc_ado.h create mode 100644 src/lib/cert/cvc/cvc_cert.cpp create mode 100644 src/lib/cert/cvc/cvc_cert.h create mode 100644 src/lib/cert/cvc/cvc_gen_cert.h create mode 100644 src/lib/cert/cvc/cvc_req.cpp create mode 100644 src/lib/cert/cvc/cvc_req.h create mode 100644 src/lib/cert/cvc/cvc_self.cpp create mode 100644 src/lib/cert/cvc/cvc_self.h create mode 100644 src/lib/cert/cvc/eac_asn_obj.h create mode 100644 src/lib/cert/cvc/eac_obj.h create mode 100644 src/lib/cert/cvc/ecdsa_sig.cpp create mode 100644 src/lib/cert/cvc/ecdsa_sig.h create mode 100644 src/lib/cert/cvc/info.txt create mode 100644 src/lib/cert/cvc/signed_obj.cpp create mode 100644 src/lib/cert/cvc/signed_obj.h create mode 100644 src/lib/cert/x509/cert_status.h create mode 100644 src/lib/cert/x509/certstor.cpp create mode 100644 src/lib/cert/x509/certstor.h create mode 100644 src/lib/cert/x509/crl_ent.cpp create mode 100644 src/lib/cert/x509/crl_ent.h create mode 100644 src/lib/cert/x509/info.txt create mode 100644 src/lib/cert/x509/key_constraint.cpp create mode 100644 src/lib/cert/x509/key_constraint.h create mode 100644 src/lib/cert/x509/ocsp.cpp create mode 100644 src/lib/cert/x509/ocsp.h create mode 100644 src/lib/cert/x509/ocsp_types.cpp create mode 100644 src/lib/cert/x509/ocsp_types.h create mode 100644 src/lib/cert/x509/pkcs10.cpp create mode 100644 src/lib/cert/x509/pkcs10.h create mode 100644 src/lib/cert/x509/x509_ca.cpp create mode 100644 src/lib/cert/x509/x509_ca.h create mode 100644 src/lib/cert/x509/x509_crl.cpp create mode 100644 src/lib/cert/x509/x509_crl.h create mode 100644 src/lib/cert/x509/x509_ext.cpp create mode 100644 src/lib/cert/x509/x509_ext.h create mode 100644 src/lib/cert/x509/x509_obj.cpp create mode 100644 src/lib/cert/x509/x509_obj.h create mode 100644 src/lib/cert/x509/x509cert.cpp create mode 100644 src/lib/cert/x509/x509cert.h create mode 100644 src/lib/cert/x509/x509opt.cpp create mode 100644 src/lib/cert/x509/x509path.cpp create mode 100644 src/lib/cert/x509/x509path.h create mode 100644 src/lib/cert/x509/x509self.cpp create mode 100644 src/lib/cert/x509/x509self.h create mode 100644 src/lib/checksum/adler32/adler32.cpp create mode 100644 src/lib/checksum/adler32/adler32.h create mode 100644 src/lib/checksum/adler32/info.txt create mode 100644 src/lib/checksum/crc24/crc24.cpp create mode 100644 src/lib/checksum/crc24/crc24.h create mode 100644 src/lib/checksum/crc24/info.txt create mode 100644 src/lib/checksum/crc32/crc32.cpp create mode 100644 src/lib/checksum/crc32/crc32.h create mode 100644 src/lib/checksum/crc32/info.txt create mode 100644 src/lib/codec/base64/base64.cpp create mode 100644 src/lib/codec/base64/base64.h create mode 100644 src/lib/codec/base64/info.txt create mode 100644 src/lib/codec/hex/hex.cpp create mode 100644 src/lib/codec/hex/hex.h create mode 100644 src/lib/codec/hex/info.txt create mode 100644 src/lib/codec/openpgp/info.txt create mode 100644 src/lib/codec/openpgp/openpgp.cpp create mode 100644 src/lib/codec/openpgp/openpgp.h create mode 100644 src/lib/codec/pem/info.txt create mode 100644 src/lib/codec/pem/pem.cpp create mode 100644 src/lib/codec/pem/pem.h create mode 100644 src/lib/constructs/aont/info.txt create mode 100644 src/lib/constructs/aont/package.cpp create mode 100644 src/lib/constructs/aont/package.h create mode 100644 src/lib/constructs/cryptobox/cryptobox.cpp create mode 100644 src/lib/constructs/cryptobox/cryptobox.h create mode 100644 src/lib/constructs/cryptobox/info.txt create mode 100644 src/lib/constructs/cryptobox_psk/cryptobox_psk.cpp create mode 100644 src/lib/constructs/cryptobox_psk/cryptobox_psk.h create mode 100644 src/lib/constructs/cryptobox_psk/info.txt create mode 100644 src/lib/constructs/fpe_fe1/fpe_fe1.cpp create mode 100644 src/lib/constructs/fpe_fe1/fpe_fe1.h create mode 100644 src/lib/constructs/fpe_fe1/info.txt create mode 100644 src/lib/constructs/rfc3394/info.txt create mode 100644 src/lib/constructs/rfc3394/rfc3394.cpp create mode 100644 src/lib/constructs/rfc3394/rfc3394.h create mode 100644 src/lib/constructs/srp6/info.txt create mode 100644 src/lib/constructs/srp6/srp6.cpp create mode 100644 src/lib/constructs/srp6/srp6.h create mode 100644 src/lib/constructs/srp6/srp6_files.cpp create mode 100644 src/lib/constructs/srp6/srp6_files.h create mode 100644 src/lib/constructs/tss/info.txt create mode 100644 src/lib/constructs/tss/tss.cpp create mode 100644 src/lib/constructs/tss/tss.h create mode 100644 src/lib/credentials/credentials_manager.cpp create mode 100644 src/lib/credentials/credentials_manager.h create mode 100644 src/lib/credentials/info.txt create mode 100644 src/lib/engine/aes_isa_eng/aes_isa_engine.cpp create mode 100644 src/lib/engine/aes_isa_eng/aes_isa_engine.h create mode 100644 src/lib/engine/aes_isa_eng/info.txt create mode 100644 src/lib/engine/asm_engine/asm_engine.cpp create mode 100644 src/lib/engine/asm_engine/asm_engine.h create mode 100644 src/lib/engine/asm_engine/info.txt create mode 100644 src/lib/engine/core_engine/core_engine.h create mode 100644 src/lib/engine/core_engine/core_modes.cpp create mode 100644 src/lib/engine/core_engine/def_pk_ops.cpp create mode 100644 src/lib/engine/core_engine/def_powm.cpp create mode 100644 src/lib/engine/core_engine/info.txt create mode 100644 src/lib/engine/core_engine/lookup_block.cpp create mode 100644 src/lib/engine/core_engine/lookup_hash.cpp create mode 100644 src/lib/engine/core_engine/lookup_mac.cpp create mode 100644 src/lib/engine/core_engine/lookup_pbkdf.cpp create mode 100644 src/lib/engine/core_engine/lookup_stream.cpp create mode 100644 src/lib/engine/dyn_engine/dyn_engine.cpp create mode 100644 src/lib/engine/dyn_engine/dyn_engine.h create mode 100644 src/lib/engine/dyn_engine/info.txt create mode 100644 src/lib/engine/engine.cpp create mode 100644 src/lib/engine/engine.h create mode 100644 src/lib/engine/gnump/gmp_mem.cpp create mode 100644 src/lib/engine/gnump/gmp_powm.cpp create mode 100644 src/lib/engine/gnump/gmp_wrap.cpp create mode 100644 src/lib/engine/gnump/gmp_wrap.h create mode 100644 src/lib/engine/gnump/gnump_engine.h create mode 100644 src/lib/engine/gnump/gnump_pk.cpp create mode 100644 src/lib/engine/gnump/info.txt create mode 100644 src/lib/engine/info.txt create mode 100644 src/lib/engine/openssl/bn_powm.cpp create mode 100644 src/lib/engine/openssl/bn_wrap.cpp create mode 100644 src/lib/engine/openssl/bn_wrap.h create mode 100644 src/lib/engine/openssl/info.txt create mode 100644 src/lib/engine/openssl/openssl_engine.h create mode 100644 src/lib/engine/openssl/ossl_arc4.cpp create mode 100644 src/lib/engine/openssl/ossl_bc.cpp create mode 100644 src/lib/engine/openssl/ossl_md.cpp create mode 100644 src/lib/engine/openssl/ossl_pk.cpp create mode 100644 src/lib/engine/simd_engine/info.txt create mode 100644 src/lib/engine/simd_engine/simd_engine.cpp create mode 100644 src/lib/engine/simd_engine/simd_engine.h create mode 100644 src/lib/entropy/beos_stats/es_beos.cpp create mode 100644 src/lib/entropy/beos_stats/es_beos.h create mode 100644 src/lib/entropy/beos_stats/info.txt create mode 100644 src/lib/entropy/cryptoapi_rng/es_capi.cpp create mode 100644 src/lib/entropy/cryptoapi_rng/es_capi.h create mode 100644 src/lib/entropy/cryptoapi_rng/info.txt create mode 100644 src/lib/entropy/dev_random/dev_random.cpp create mode 100644 src/lib/entropy/dev_random/dev_random.h create mode 100644 src/lib/entropy/dev_random/info.txt create mode 100644 src/lib/entropy/egd/es_egd.cpp create mode 100644 src/lib/entropy/egd/es_egd.h create mode 100644 src/lib/entropy/egd/info.txt create mode 100644 src/lib/entropy/entropy_src.h create mode 100644 src/lib/entropy/hres_timer/hres_timer.cpp create mode 100644 src/lib/entropy/hres_timer/hres_timer.h create mode 100644 src/lib/entropy/hres_timer/info.txt create mode 100644 src/lib/entropy/info.txt create mode 100644 src/lib/entropy/proc_walk/info.txt create mode 100644 src/lib/entropy/proc_walk/proc_walk.cpp create mode 100644 src/lib/entropy/proc_walk/proc_walk.h create mode 100644 src/lib/entropy/rdrand/info.txt create mode 100644 src/lib/entropy/rdrand/rdrand.cpp create mode 100644 src/lib/entropy/rdrand/rdrand.h create mode 100644 src/lib/entropy/unix_procs/info.txt create mode 100644 src/lib/entropy/unix_procs/unix_proc_sources.cpp create mode 100644 src/lib/entropy/unix_procs/unix_procs.cpp create mode 100644 src/lib/entropy/unix_procs/unix_procs.h create mode 100644 src/lib/entropy/win32_stats/es_win32.cpp create mode 100644 src/lib/entropy/win32_stats/es_win32.h create mode 100644 src/lib/entropy/win32_stats/info.txt create mode 100644 src/lib/filters/aead_filt/aead_filt.h create mode 100644 src/lib/filters/aead_filt/info.txt create mode 100644 src/lib/filters/algo_filt.cpp create mode 100644 src/lib/filters/basefilt.cpp create mode 100644 src/lib/filters/basefilt.h create mode 100644 src/lib/filters/buf_filt.cpp create mode 100644 src/lib/filters/buf_filt.h create mode 100644 src/lib/filters/codec_filt/b64_filt.cpp create mode 100644 src/lib/filters/codec_filt/b64_filt.h create mode 100644 src/lib/filters/codec_filt/hex_filt.cpp create mode 100644 src/lib/filters/codec_filt/hex_filt.h create mode 100644 src/lib/filters/codec_filt/info.txt create mode 100644 src/lib/filters/compression/bzip2/bzip2.cpp create mode 100644 src/lib/filters/compression/bzip2/bzip2.h create mode 100644 src/lib/filters/compression/bzip2/info.txt create mode 100644 src/lib/filters/compression/lzma/info.txt create mode 100644 src/lib/filters/compression/lzma/lzma.cpp create mode 100644 src/lib/filters/compression/lzma/lzma.h create mode 100644 src/lib/filters/compression/zlib/info.txt create mode 100644 src/lib/filters/compression/zlib/zlib.cpp create mode 100644 src/lib/filters/compression/zlib/zlib.h create mode 100644 src/lib/filters/data_snk.cpp create mode 100644 src/lib/filters/data_snk.h create mode 100644 src/lib/filters/data_src.cpp create mode 100644 src/lib/filters/data_src.h create mode 100644 src/lib/filters/fd_unix/fd_unix.cpp create mode 100644 src/lib/filters/fd_unix/fd_unix.h create mode 100644 src/lib/filters/fd_unix/info.txt create mode 100644 src/lib/filters/filter.cpp create mode 100644 src/lib/filters/filter.h create mode 100644 src/lib/filters/filters.h create mode 100644 src/lib/filters/info.txt create mode 100644 src/lib/filters/key_filt.h create mode 100644 src/lib/filters/out_buf.cpp create mode 100644 src/lib/filters/out_buf.h create mode 100644 src/lib/filters/pipe.cpp create mode 100644 src/lib/filters/pipe.h create mode 100644 src/lib/filters/pipe_io.cpp create mode 100644 src/lib/filters/pipe_rw.cpp create mode 100644 src/lib/filters/pk_filts/info.txt create mode 100644 src/lib/filters/pk_filts/pk_filts.cpp create mode 100644 src/lib/filters/pk_filts/pk_filts.h create mode 100644 src/lib/filters/secqueue.cpp create mode 100644 src/lib/filters/secqueue.h create mode 100644 src/lib/filters/threaded_fork.cpp create mode 100644 src/lib/filters/transform_filter.cpp create mode 100644 src/lib/filters/transform_filter.h create mode 100644 src/lib/hash/bmw_512/bmw_512.cpp create mode 100644 src/lib/hash/bmw_512/bmw_512.h create mode 100644 src/lib/hash/bmw_512/info.txt create mode 100644 src/lib/hash/comb4p/comb4p.cpp create mode 100644 src/lib/hash/comb4p/comb4p.h create mode 100644 src/lib/hash/comb4p/info.txt create mode 100644 src/lib/hash/gost_3411/gost_3411.cpp create mode 100644 src/lib/hash/gost_3411/gost_3411.h create mode 100644 src/lib/hash/gost_3411/info.txt create mode 100644 src/lib/hash/has160/has160.cpp create mode 100644 src/lib/hash/has160/has160.h create mode 100644 src/lib/hash/has160/info.txt create mode 100644 src/lib/hash/hash.h create mode 100644 src/lib/hash/info.txt create mode 100644 src/lib/hash/keccak/info.txt create mode 100644 src/lib/hash/keccak/keccak.cpp create mode 100644 src/lib/hash/keccak/keccak.h create mode 100644 src/lib/hash/md2/info.txt create mode 100644 src/lib/hash/md2/md2.cpp create mode 100644 src/lib/hash/md2/md2.h create mode 100644 src/lib/hash/md4/info.txt create mode 100644 src/lib/hash/md4/md4.cpp create mode 100644 src/lib/hash/md4/md4.h create mode 100644 src/lib/hash/md4_x86_32/info.txt create mode 100644 src/lib/hash/md4_x86_32/md4_x86_32.cpp create mode 100644 src/lib/hash/md4_x86_32/md4_x86_32.h create mode 100644 src/lib/hash/md4_x86_32/md4_x86_32_imp.S create mode 100644 src/lib/hash/md5/info.txt create mode 100644 src/lib/hash/md5/md5.cpp create mode 100644 src/lib/hash/md5/md5.h create mode 100644 src/lib/hash/md5_x86_32/info.txt create mode 100644 src/lib/hash/md5_x86_32/md5_x86_32.cpp create mode 100644 src/lib/hash/md5_x86_32/md5_x86_32.h create mode 100644 src/lib/hash/md5_x86_32/md5_x86_32_imp.S create mode 100644 src/lib/hash/mdx_hash/info.txt create mode 100644 src/lib/hash/mdx_hash/mdx_hash.cpp create mode 100644 src/lib/hash/mdx_hash/mdx_hash.h create mode 100644 src/lib/hash/par_hash/info.txt create mode 100644 src/lib/hash/par_hash/par_hash.cpp create mode 100644 src/lib/hash/par_hash/par_hash.h create mode 100644 src/lib/hash/rmd128/info.txt create mode 100644 src/lib/hash/rmd128/rmd128.cpp create mode 100644 src/lib/hash/rmd128/rmd128.h create mode 100644 src/lib/hash/rmd160/info.txt create mode 100644 src/lib/hash/rmd160/rmd160.cpp create mode 100644 src/lib/hash/rmd160/rmd160.h create mode 100644 src/lib/hash/sha1/info.txt create mode 100644 src/lib/hash/sha1/sha160.cpp create mode 100644 src/lib/hash/sha1/sha160.h create mode 100644 src/lib/hash/sha1_sse2/info.txt create mode 100644 src/lib/hash/sha1_sse2/sha1_sse2.cpp create mode 100644 src/lib/hash/sha1_sse2/sha1_sse2.h create mode 100644 src/lib/hash/sha1_x86_32/info.txt create mode 100644 src/lib/hash/sha1_x86_32/sha1_x86_32.cpp create mode 100644 src/lib/hash/sha1_x86_32/sha1_x86_32.h create mode 100644 src/lib/hash/sha1_x86_32/sha1_x86_32_imp.S create mode 100644 src/lib/hash/sha1_x86_64/info.txt create mode 100644 src/lib/hash/sha1_x86_64/sha1_x86_64.cpp create mode 100644 src/lib/hash/sha1_x86_64/sha1_x86_64.h create mode 100644 src/lib/hash/sha1_x86_64/sha1_x86_64_imp.S create mode 100644 src/lib/hash/sha2_32/info.txt create mode 100644 src/lib/hash/sha2_32/sha2_32.cpp create mode 100644 src/lib/hash/sha2_32/sha2_32.h create mode 100644 src/lib/hash/sha2_64/info.txt create mode 100644 src/lib/hash/sha2_64/sha2_64.cpp create mode 100644 src/lib/hash/sha2_64/sha2_64.h create mode 100644 src/lib/hash/skein/info.txt create mode 100644 src/lib/hash/skein/skein_512.cpp create mode 100644 src/lib/hash/skein/skein_512.h create mode 100644 src/lib/hash/tiger/info.txt create mode 100644 src/lib/hash/tiger/tig_tab.cpp create mode 100644 src/lib/hash/tiger/tiger.cpp create mode 100644 src/lib/hash/tiger/tiger.h create mode 100644 src/lib/hash/whirlpool/info.txt create mode 100644 src/lib/hash/whirlpool/whrl_tab.cpp create mode 100644 src/lib/hash/whirlpool/whrlpool.cpp create mode 100644 src/lib/hash/whirlpool/whrlpool.h create mode 100644 src/lib/kdf/info.txt create mode 100644 src/lib/kdf/kdf.cpp create mode 100644 src/lib/kdf/kdf.h create mode 100644 src/lib/kdf/kdf1/info.txt create mode 100644 src/lib/kdf/kdf1/kdf1.cpp create mode 100644 src/lib/kdf/kdf1/kdf1.h create mode 100644 src/lib/kdf/kdf2/info.txt create mode 100644 src/lib/kdf/kdf2/kdf2.cpp create mode 100644 src/lib/kdf/kdf2/kdf2.h create mode 100644 src/lib/kdf/mgf1/info.txt create mode 100644 src/lib/kdf/mgf1/mgf1.cpp create mode 100644 src/lib/kdf/mgf1/mgf1.h create mode 100644 src/lib/kdf/prf_ssl3/info.txt create mode 100644 src/lib/kdf/prf_ssl3/prf_ssl3.cpp create mode 100644 src/lib/kdf/prf_ssl3/prf_ssl3.h create mode 100644 src/lib/kdf/prf_tls/info.txt create mode 100644 src/lib/kdf/prf_tls/prf_tls.cpp create mode 100644 src/lib/kdf/prf_tls/prf_tls.h create mode 100644 src/lib/kdf/prf_x942/info.txt create mode 100644 src/lib/kdf/prf_x942/prf_x942.cpp create mode 100644 src/lib/kdf/prf_x942/prf_x942.h create mode 100644 src/lib/libstate/botan.h create mode 100644 src/lib/libstate/global_rng.cpp create mode 100644 src/lib/libstate/global_state.cpp create mode 100644 src/lib/libstate/global_state.h create mode 100644 src/lib/libstate/info.txt create mode 100644 src/lib/libstate/init.cpp create mode 100644 src/lib/libstate/init.h create mode 100644 src/lib/libstate/libstate.cpp create mode 100644 src/lib/libstate/libstate.h create mode 100644 src/lib/libstate/lookup.cpp create mode 100644 src/lib/libstate/lookup.h create mode 100644 src/lib/mac/cbc_mac/cbc_mac.cpp create mode 100644 src/lib/mac/cbc_mac/cbc_mac.h create mode 100644 src/lib/mac/cbc_mac/info.txt create mode 100644 src/lib/mac/cmac/cmac.cpp create mode 100644 src/lib/mac/cmac/cmac.h create mode 100644 src/lib/mac/cmac/info.txt create mode 100644 src/lib/mac/hmac/hmac.cpp create mode 100644 src/lib/mac/hmac/hmac.h create mode 100644 src/lib/mac/hmac/info.txt create mode 100644 src/lib/mac/info.txt create mode 100644 src/lib/mac/mac.cpp create mode 100644 src/lib/mac/mac.h create mode 100644 src/lib/mac/ssl3mac/info.txt create mode 100644 src/lib/mac/ssl3mac/ssl3_mac.cpp create mode 100644 src/lib/mac/ssl3mac/ssl3_mac.h create mode 100644 src/lib/mac/x919_mac/info.txt create mode 100644 src/lib/mac/x919_mac/x919_mac.cpp create mode 100644 src/lib/mac/x919_mac/x919_mac.h create mode 100644 src/lib/math/bigint/big_code.cpp create mode 100644 src/lib/math/bigint/big_io.cpp create mode 100644 src/lib/math/bigint/big_ops2.cpp create mode 100644 src/lib/math/bigint/big_ops3.cpp create mode 100644 src/lib/math/bigint/big_rand.cpp create mode 100644 src/lib/math/bigint/bigint.cpp create mode 100644 src/lib/math/bigint/bigint.h create mode 100644 src/lib/math/bigint/divide.cpp create mode 100644 src/lib/math/bigint/divide.h create mode 100644 src/lib/math/bigint/info.txt create mode 100644 src/lib/math/ec_gfp/curve_gfp.h create mode 100644 src/lib/math/ec_gfp/info.txt create mode 100644 src/lib/math/ec_gfp/point_gfp.cpp create mode 100644 src/lib/math/ec_gfp/point_gfp.h create mode 100644 src/lib/math/mp/info.txt create mode 100644 src/lib/math/mp/mp_asm.cpp create mode 100644 src/lib/math/mp/mp_comba.cpp create mode 100644 src/lib/math/mp/mp_core.h create mode 100644 src/lib/math/mp/mp_generic/info.txt create mode 100644 src/lib/math/mp/mp_generic/mp_asmi.h create mode 100644 src/lib/math/mp/mp_generic/mp_madd.h create mode 100644 src/lib/math/mp/mp_karat.cpp create mode 100644 src/lib/math/mp/mp_misc.cpp create mode 100644 src/lib/math/mp/mp_monty.cpp create mode 100644 src/lib/math/mp/mp_mulop.cpp create mode 100644 src/lib/math/mp/mp_shift.cpp create mode 100644 src/lib/math/mp/mp_types.h create mode 100644 src/lib/math/mp/mp_x86_32/info.txt create mode 100644 src/lib/math/mp/mp_x86_32/mp_asmi.h create mode 100644 src/lib/math/mp/mp_x86_32/mp_madd.h create mode 100644 src/lib/math/mp/mp_x86_32_msvc/info.txt create mode 100644 src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h create mode 100644 src/lib/math/mp/mp_x86_64/info.txt create mode 100644 src/lib/math/mp/mp_x86_64/mp_asmi.h create mode 100644 src/lib/math/mp/mp_x86_64/mp_madd.h create mode 100644 src/lib/math/numbertheory/def_powm.h create mode 100644 src/lib/math/numbertheory/dsa_gen.cpp create mode 100644 src/lib/math/numbertheory/info.txt create mode 100644 src/lib/math/numbertheory/jacobi.cpp create mode 100644 src/lib/math/numbertheory/make_prm.cpp create mode 100644 src/lib/math/numbertheory/mp_numth.cpp create mode 100644 src/lib/math/numbertheory/numthry.cpp create mode 100644 src/lib/math/numbertheory/numthry.h create mode 100644 src/lib/math/numbertheory/pow_mod.cpp create mode 100644 src/lib/math/numbertheory/pow_mod.h create mode 100644 src/lib/math/numbertheory/powm_fw.cpp create mode 100644 src/lib/math/numbertheory/powm_mnt.cpp create mode 100644 src/lib/math/numbertheory/primes.cpp create mode 100644 src/lib/math/numbertheory/reducer.cpp create mode 100644 src/lib/math/numbertheory/reducer.h create mode 100644 src/lib/math/numbertheory/ressol.cpp create mode 100644 src/lib/modes/aead/aead.cpp create mode 100644 src/lib/modes/aead/aead.h create mode 100644 src/lib/modes/aead/ccm/ccm.cpp create mode 100644 src/lib/modes/aead/ccm/ccm.h create mode 100644 src/lib/modes/aead/ccm/info.txt create mode 100644 src/lib/modes/aead/eax/eax.cpp create mode 100644 src/lib/modes/aead/eax/eax.h create mode 100644 src/lib/modes/aead/eax/info.txt create mode 100644 src/lib/modes/aead/gcm/clmul/clmul.cpp create mode 100644 src/lib/modes/aead/gcm/clmul/clmul.h create mode 100644 src/lib/modes/aead/gcm/clmul/info.txt create mode 100644 src/lib/modes/aead/gcm/gcm.cpp create mode 100644 src/lib/modes/aead/gcm/gcm.h create mode 100644 src/lib/modes/aead/gcm/info.txt create mode 100644 src/lib/modes/aead/info.txt create mode 100644 src/lib/modes/aead/ocb/info.txt create mode 100644 src/lib/modes/aead/ocb/ocb.cpp create mode 100644 src/lib/modes/aead/ocb/ocb.h create mode 100644 src/lib/modes/aead/siv/info.txt create mode 100644 src/lib/modes/aead/siv/siv.cpp create mode 100644 src/lib/modes/aead/siv/siv.h create mode 100644 src/lib/modes/cbc/cbc.cpp create mode 100644 src/lib/modes/cbc/cbc.h create mode 100644 src/lib/modes/cbc/info.txt create mode 100644 src/lib/modes/cfb/cfb.cpp create mode 100644 src/lib/modes/cfb/cfb.h create mode 100644 src/lib/modes/cfb/info.txt create mode 100644 src/lib/modes/cipher_mode.h create mode 100644 src/lib/modes/ecb/ecb.cpp create mode 100644 src/lib/modes/ecb/ecb.h create mode 100644 src/lib/modes/ecb/info.txt create mode 100644 src/lib/modes/info.txt create mode 100644 src/lib/modes/mode_pad/info.txt create mode 100644 src/lib/modes/mode_pad/mode_pad.cpp create mode 100644 src/lib/modes/mode_pad/mode_pad.h create mode 100644 src/lib/modes/xts/info.txt create mode 100644 src/lib/modes/xts/xts.cpp create mode 100644 src/lib/modes/xts/xts.h create mode 100644 src/lib/passhash/bcrypt/bcrypt.cpp create mode 100644 src/lib/passhash/bcrypt/bcrypt.h create mode 100644 src/lib/passhash/bcrypt/info.txt create mode 100644 src/lib/passhash/passhash9/info.txt create mode 100644 src/lib/passhash/passhash9/passhash9.cpp create mode 100644 src/lib/passhash/passhash9/passhash9.h create mode 100644 src/lib/pbe/get_pbe.cpp create mode 100644 src/lib/pbe/get_pbe.h create mode 100644 src/lib/pbe/info.txt create mode 100644 src/lib/pbe/pbe.h create mode 100644 src/lib/pbe/pbes1/info.txt create mode 100644 src/lib/pbe/pbes1/pbes1.cpp create mode 100644 src/lib/pbe/pbes1/pbes1.h create mode 100644 src/lib/pbe/pbes2/info.txt create mode 100644 src/lib/pbe/pbes2/pbes2.cpp create mode 100644 src/lib/pbe/pbes2/pbes2.h create mode 100644 src/lib/pbkdf/info.txt create mode 100644 src/lib/pbkdf/pbkdf.cpp create mode 100644 src/lib/pbkdf/pbkdf.h create mode 100644 src/lib/pbkdf/pbkdf1/info.txt create mode 100644 src/lib/pbkdf/pbkdf1/pbkdf1.cpp create mode 100644 src/lib/pbkdf/pbkdf1/pbkdf1.h create mode 100644 src/lib/pbkdf/pbkdf2/info.txt create mode 100644 src/lib/pbkdf/pbkdf2/pbkdf2.cpp create mode 100644 src/lib/pbkdf/pbkdf2/pbkdf2.h create mode 100644 src/lib/pk_pad/eme.cpp create mode 100644 src/lib/pk_pad/eme.h create mode 100644 src/lib/pk_pad/eme1/eme1.cpp create mode 100644 src/lib/pk_pad/eme1/eme1.h create mode 100644 src/lib/pk_pad/eme1/info.txt create mode 100644 src/lib/pk_pad/eme_pkcs/eme_pkcs.cpp create mode 100644 src/lib/pk_pad/eme_pkcs/eme_pkcs.h create mode 100644 src/lib/pk_pad/eme_pkcs/info.txt create mode 100644 src/lib/pk_pad/emsa.h create mode 100644 src/lib/pk_pad/emsa1/emsa1.cpp create mode 100644 src/lib/pk_pad/emsa1/emsa1.h create mode 100644 src/lib/pk_pad/emsa1/info.txt create mode 100644 src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp create mode 100644 src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h create mode 100644 src/lib/pk_pad/emsa1_bsi/info.txt create mode 100644 src/lib/pk_pad/emsa2/emsa2.cpp create mode 100644 src/lib/pk_pad/emsa2/emsa2.h create mode 100644 src/lib/pk_pad/emsa2/info.txt create mode 100644 src/lib/pk_pad/emsa3/emsa3.cpp create mode 100644 src/lib/pk_pad/emsa3/emsa3.h create mode 100644 src/lib/pk_pad/emsa3/info.txt create mode 100644 src/lib/pk_pad/emsa4/emsa4.cpp create mode 100644 src/lib/pk_pad/emsa4/emsa4.h create mode 100644 src/lib/pk_pad/emsa4/info.txt create mode 100644 src/lib/pk_pad/emsa_raw/emsa_raw.cpp create mode 100644 src/lib/pk_pad/emsa_raw/emsa_raw.h create mode 100644 src/lib/pk_pad/emsa_raw/info.txt create mode 100644 src/lib/pk_pad/get_pk_pad.cpp create mode 100644 src/lib/pk_pad/hash_id/hash_id.cpp create mode 100644 src/lib/pk_pad/hash_id/hash_id.h create mode 100644 src/lib/pk_pad/hash_id/info.txt create mode 100644 src/lib/pk_pad/info.txt create mode 100644 src/lib/prf/hkdf/hkdf.cpp create mode 100644 src/lib/prf/hkdf/hkdf.h create mode 100644 src/lib/prf/hkdf/info.txt create mode 100644 src/lib/pubkey/blinding.cpp create mode 100644 src/lib/pubkey/blinding.h create mode 100644 src/lib/pubkey/dh/dh.cpp create mode 100644 src/lib/pubkey/dh/dh.h create mode 100644 src/lib/pubkey/dh/info.txt create mode 100644 src/lib/pubkey/dl_algo/dl_algo.cpp create mode 100644 src/lib/pubkey/dl_algo/dl_algo.h create mode 100644 src/lib/pubkey/dl_algo/info.txt create mode 100644 src/lib/pubkey/dl_group/dl_group.cpp create mode 100644 src/lib/pubkey/dl_group/dl_group.h create mode 100644 src/lib/pubkey/dl_group/info.txt create mode 100644 src/lib/pubkey/dl_group/named.cpp create mode 100644 src/lib/pubkey/dlies/dlies.cpp create mode 100644 src/lib/pubkey/dlies/dlies.h create mode 100644 src/lib/pubkey/dlies/info.txt create mode 100644 src/lib/pubkey/dsa/dsa.cpp create mode 100644 src/lib/pubkey/dsa/dsa.h create mode 100644 src/lib/pubkey/dsa/info.txt create mode 100644 src/lib/pubkey/ec_group/ec_group.cpp create mode 100644 src/lib/pubkey/ec_group/ec_group.h create mode 100644 src/lib/pubkey/ec_group/info.txt create mode 100644 src/lib/pubkey/ec_group/named.cpp create mode 100644 src/lib/pubkey/ecc_key/ecc_key.cpp create mode 100644 src/lib/pubkey/ecc_key/ecc_key.h create mode 100644 src/lib/pubkey/ecc_key/info.txt create mode 100644 src/lib/pubkey/ecdh/ecdh.cpp create mode 100644 src/lib/pubkey/ecdh/ecdh.h create mode 100644 src/lib/pubkey/ecdh/info.txt create mode 100644 src/lib/pubkey/ecdsa/ecdsa.cpp create mode 100644 src/lib/pubkey/ecdsa/ecdsa.h create mode 100644 src/lib/pubkey/ecdsa/info.txt create mode 100644 src/lib/pubkey/elgamal/elgamal.cpp create mode 100644 src/lib/pubkey/elgamal/elgamal.h create mode 100644 src/lib/pubkey/elgamal/info.txt create mode 100644 src/lib/pubkey/gost_3410/gost_3410.cpp create mode 100644 src/lib/pubkey/gost_3410/gost_3410.h create mode 100644 src/lib/pubkey/gost_3410/info.txt create mode 100644 src/lib/pubkey/if_algo/if_algo.cpp create mode 100644 src/lib/pubkey/if_algo/if_algo.h create mode 100644 src/lib/pubkey/if_algo/info.txt create mode 100644 src/lib/pubkey/info.txt create mode 100644 src/lib/pubkey/keypair/info.txt create mode 100644 src/lib/pubkey/keypair/keypair.cpp create mode 100644 src/lib/pubkey/keypair/keypair.h create mode 100644 src/lib/pubkey/nr/info.txt create mode 100644 src/lib/pubkey/nr/nr.cpp create mode 100644 src/lib/pubkey/nr/nr.h create mode 100644 src/lib/pubkey/pk_algs.cpp create mode 100644 src/lib/pubkey/pk_algs.h create mode 100644 src/lib/pubkey/pk_keys.cpp create mode 100644 src/lib/pubkey/pk_keys.h create mode 100644 src/lib/pubkey/pk_ops.h create mode 100644 src/lib/pubkey/pkcs8.cpp create mode 100644 src/lib/pubkey/pkcs8.h create mode 100644 src/lib/pubkey/pubkey.cpp create mode 100644 src/lib/pubkey/pubkey.h create mode 100644 src/lib/pubkey/rsa/info.txt create mode 100644 src/lib/pubkey/rsa/rsa.cpp create mode 100644 src/lib/pubkey/rsa/rsa.h create mode 100644 src/lib/pubkey/rw/info.txt create mode 100644 src/lib/pubkey/rw/rw.cpp create mode 100644 src/lib/pubkey/rw/rw.h create mode 100644 src/lib/pubkey/workfactor.cpp create mode 100644 src/lib/pubkey/workfactor.h create mode 100644 src/lib/pubkey/x509_key.cpp create mode 100644 src/lib/pubkey/x509_key.h create mode 100644 src/lib/rng/auto_rng/auto_rng.h create mode 100644 src/lib/rng/auto_rng/info.txt create mode 100644 src/lib/rng/hmac_rng/hmac_rng.cpp create mode 100644 src/lib/rng/hmac_rng/hmac_rng.h create mode 100644 src/lib/rng/hmac_rng/info.txt create mode 100644 src/lib/rng/info.txt create mode 100644 src/lib/rng/rng.cpp create mode 100644 src/lib/rng/rng.h create mode 100644 src/lib/rng/x931_rng/info.txt create mode 100644 src/lib/rng/x931_rng/x931_rng.cpp create mode 100644 src/lib/rng/x931_rng/x931_rng.h create mode 100644 src/lib/selftest/info.txt create mode 100644 src/lib/selftest/selftest.cpp create mode 100644 src/lib/selftest/selftest.h create mode 100644 src/lib/simd/info.txt create mode 100644 src/lib/simd/simd_32.h create mode 100644 src/lib/simd/simd_altivec/info.txt create mode 100644 src/lib/simd/simd_altivec/simd_altivec.h create mode 100644 src/lib/simd/simd_scalar/info.txt create mode 100644 src/lib/simd/simd_scalar/simd_scalar.h create mode 100644 src/lib/simd/simd_sse2/info.txt create mode 100644 src/lib/simd/simd_sse2/simd_sse2.h create mode 100644 src/lib/stream/ctr/ctr.cpp create mode 100644 src/lib/stream/ctr/ctr.h create mode 100644 src/lib/stream/ctr/info.txt create mode 100644 src/lib/stream/info.txt create mode 100644 src/lib/stream/ofb/info.txt create mode 100644 src/lib/stream/ofb/ofb.cpp create mode 100644 src/lib/stream/ofb/ofb.h create mode 100644 src/lib/stream/rc4/info.txt create mode 100644 src/lib/stream/rc4/rc4.cpp create mode 100644 src/lib/stream/rc4/rc4.h create mode 100644 src/lib/stream/salsa20/info.txt create mode 100644 src/lib/stream/salsa20/salsa20.cpp create mode 100644 src/lib/stream/salsa20/salsa20.h create mode 100644 src/lib/stream/stream_cipher.cpp create mode 100644 src/lib/stream/stream_cipher.h create mode 100644 src/lib/tls/info.txt create mode 100644 src/lib/tls/msg_cert_req.cpp create mode 100644 src/lib/tls/msg_cert_verify.cpp create mode 100644 src/lib/tls/msg_certificate.cpp create mode 100644 src/lib/tls/msg_client_hello.cpp create mode 100644 src/lib/tls/msg_client_kex.cpp create mode 100644 src/lib/tls/msg_finished.cpp create mode 100644 src/lib/tls/msg_hello_verify.cpp create mode 100644 src/lib/tls/msg_next_protocol.cpp create mode 100644 src/lib/tls/msg_server_hello.cpp create mode 100644 src/lib/tls/msg_server_kex.cpp create mode 100644 src/lib/tls/msg_session_ticket.cpp create mode 100644 src/lib/tls/sessions_sqlite/info.txt create mode 100644 src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.cpp create mode 100644 src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.h create mode 100644 src/lib/tls/tls_alert.cpp create mode 100644 src/lib/tls/tls_alert.h create mode 100644 src/lib/tls/tls_blocking.cpp create mode 100644 src/lib/tls/tls_blocking.h create mode 100644 src/lib/tls/tls_channel.cpp create mode 100644 src/lib/tls/tls_channel.h create mode 100644 src/lib/tls/tls_ciphersuite.cpp create mode 100644 src/lib/tls/tls_ciphersuite.h create mode 100644 src/lib/tls/tls_client.cpp create mode 100644 src/lib/tls/tls_client.h create mode 100644 src/lib/tls/tls_exceptn.h create mode 100644 src/lib/tls/tls_extensions.cpp create mode 100644 src/lib/tls/tls_extensions.h create mode 100644 src/lib/tls/tls_handshake_hash.cpp create mode 100644 src/lib/tls/tls_handshake_hash.h create mode 100644 src/lib/tls/tls_handshake_io.cpp create mode 100644 src/lib/tls/tls_handshake_io.h create mode 100644 src/lib/tls/tls_handshake_msg.h create mode 100644 src/lib/tls/tls_handshake_state.cpp create mode 100644 src/lib/tls/tls_handshake_state.h create mode 100644 src/lib/tls/tls_heartbeats.cpp create mode 100644 src/lib/tls/tls_heartbeats.h create mode 100644 src/lib/tls/tls_magic.h create mode 100644 src/lib/tls/tls_messages.h create mode 100644 src/lib/tls/tls_policy.cpp create mode 100644 src/lib/tls/tls_policy.h create mode 100644 src/lib/tls/tls_reader.h create mode 100644 src/lib/tls/tls_record.cpp create mode 100644 src/lib/tls/tls_record.h create mode 100644 src/lib/tls/tls_seq_numbers.h create mode 100644 src/lib/tls/tls_server.cpp create mode 100644 src/lib/tls/tls_server.h create mode 100644 src/lib/tls/tls_server_info.h create mode 100644 src/lib/tls/tls_session.cpp create mode 100644 src/lib/tls/tls_session.h create mode 100644 src/lib/tls/tls_session_key.cpp create mode 100644 src/lib/tls/tls_session_key.h create mode 100644 src/lib/tls/tls_session_manager.h create mode 100644 src/lib/tls/tls_session_manager_memory.cpp create mode 100644 src/lib/tls/tls_suite_info.cpp create mode 100644 src/lib/tls/tls_version.cpp create mode 100644 src/lib/tls/tls_version.h create mode 100644 src/lib/utils/asm_x86_32/asm_x86_32.h create mode 100644 src/lib/utils/asm_x86_32/info.txt create mode 100644 src/lib/utils/asm_x86_64/asm_x86_64.h create mode 100644 src/lib/utils/asm_x86_64/info.txt create mode 100644 src/lib/utils/assert.cpp create mode 100644 src/lib/utils/assert.h create mode 100644 src/lib/utils/bit_ops.h create mode 100644 src/lib/utils/boost/info.txt create mode 100644 src/lib/utils/bswap.h create mode 100644 src/lib/utils/calendar.cpp create mode 100644 src/lib/utils/calendar.h create mode 100644 src/lib/utils/charset.cpp create mode 100644 src/lib/utils/charset.h create mode 100644 src/lib/utils/cpuid.cpp create mode 100644 src/lib/utils/cpuid.h create mode 100644 src/lib/utils/datastor/datastor.cpp create mode 100644 src/lib/utils/datastor/datastor.h create mode 100644 src/lib/utils/datastor/info.txt create mode 100644 src/lib/utils/dyn_load/dyn_load.cpp create mode 100644 src/lib/utils/dyn_load/dyn_load.h create mode 100644 src/lib/utils/dyn_load/info.txt create mode 100644 src/lib/utils/exceptn.h create mode 100644 src/lib/utils/get_byte.h create mode 100644 src/lib/utils/http_util/http_util.cpp create mode 100644 src/lib/utils/http_util/http_util.h create mode 100644 src/lib/utils/http_util/info.txt create mode 100644 src/lib/utils/info.txt create mode 100644 src/lib/utils/loadstor.h create mode 100644 src/lib/utils/mem_ops.h create mode 100644 src/lib/utils/mul128.h create mode 100644 src/lib/utils/parsing.cpp create mode 100644 src/lib/utils/parsing.h create mode 100644 src/lib/utils/prefetch.h create mode 100644 src/lib/utils/read_cfg.cpp create mode 100644 src/lib/utils/rotate.h create mode 100644 src/lib/utils/rounding.h create mode 100644 src/lib/utils/semaphore.cpp create mode 100644 src/lib/utils/semaphore.h create mode 100644 src/lib/utils/sqlite3/info.txt create mode 100644 src/lib/utils/sqlite3/sqlite3.cpp create mode 100644 src/lib/utils/sqlite3/sqlite3.h create mode 100644 src/lib/utils/stl_util.h create mode 100644 src/lib/utils/types.h create mode 100644 src/lib/utils/version.cpp create mode 100644 src/lib/utils/version.h create mode 100644 src/lib/utils/xor_buf.h create mode 100644 src/lib/utils/zero_mem.cpp (limited to 'src') diff --git a/src/lib/algo_base/algo_base.h b/src/lib/algo_base/algo_base.h new file mode 100644 index 000000000..f757a9a83 --- /dev/null +++ b/src/lib/algo_base/algo_base.h @@ -0,0 +1,41 @@ +/* +* Algorithm Base Class +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ALGO_BASE_CLASS_H__ +#define BOTAN_ALGO_BASE_CLASS_H__ + +#include +#include + +namespace Botan { + +/** +* This class represents an algorithm of some kind +*/ +class BOTAN_DLL Algorithm + { + public: + /** + * Zeroize internal state + */ + virtual void clear() = 0; + + /** + * @return name of this algorithm + */ + virtual std::string name() const = 0; + + Algorithm() {} + Algorithm(const Algorithm&) = delete; + Algorithm& operator=(const Algorithm&) = delete; + + virtual ~Algorithm() {} + }; + +} + +#endif diff --git a/src/lib/algo_base/buf_comp.h b/src/lib/algo_base/buf_comp.h new file mode 100644 index 000000000..f25af3b92 --- /dev/null +++ b/src/lib/algo_base/buf_comp.h @@ -0,0 +1,171 @@ +/* +* Buffered Computation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BUFFERED_COMPUTATION_H__ +#define BOTAN_BUFFERED_COMPUTATION_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents any kind of computation which uses an internal +* state, such as hash functions or MACs +*/ +class BOTAN_DLL Buffered_Computation + { + public: + /** + * @return length of the output of this function in bytes + */ + virtual size_t output_length() const = 0; + + /** + * Add new input to process. + * @param in the input to process as a byte array + * @param length of param in in bytes + */ + void update(const byte in[], size_t length) { add_data(in, length); } + + /** + * Add new input to process. + * @param in the input to process as a secure_vector + */ + void update(const secure_vector& in) + { + add_data(&in[0], in.size()); + } + + /** + * Add new input to process. + * @param in the input to process as a std::vector + */ + void update(const std::vector& in) + { + add_data(&in[0], in.size()); + } + + /** + * Add an integer in big-endian order + * @param in the value + */ + template void update_be(const T in) + { + for(size_t i = 0; i != sizeof(T); ++i) + { + byte b = get_byte(i, in); + add_data(&b, 1); + } + } + + /** + * Add new input to process. + * @param str the input to process as a std::string. Will be interpreted + * as a byte array based on + * the strings encoding. + */ + void update(const std::string& str) + { + add_data(reinterpret_cast(str.data()), str.size()); + } + + /** + * Process a single byte. + * @param in the byte to process + */ + void update(byte in) { add_data(&in, 1); } + + /** + * Complete the computation and retrieve the + * final result. + * @param out The byte array to be filled with the result. + * Must be of length output_length() + */ + void final(byte out[]) { final_result(out); } + + /** + * Complete the computation and retrieve the + * final result. + * @return secure_vector holding the result + */ + secure_vector final() + { + secure_vector output(output_length()); + final_result(&output[0]); + return output; + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a byte array + * @param length the length of the byte array + * @result the result of the call to final() + */ + secure_vector process(const byte in[], size_t length) + { + add_data(in, length); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector process(const secure_vector& in) + { + add_data(&in[0], in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector process(const std::vector& in) + { + add_data(&in[0], in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a string + * @result the result of the call to final() + */ + secure_vector process(const std::string& in) + { + update(in); + return final(); + } + + virtual ~Buffered_Computation() {} + private: + /** + * Add more data to the computation + * @param input is an input buffer + * @param length is the length of input in bytes + */ + virtual void add_data(const byte input[], size_t length) = 0; + + /** + * Write the final output to out + * @param out is an output buffer of output_length() + */ + virtual void final_result(byte out[]) = 0; + }; + +} + +#endif diff --git a/src/lib/algo_base/info.txt b/src/lib/algo_base/info.txt new file mode 100644 index 000000000..a2c509f2c --- /dev/null +++ b/src/lib/algo_base/info.txt @@ -0,0 +1,8 @@ +define TRANSFORM 20131209 + + +alloc +filters +hex +rng + diff --git a/src/lib/algo_base/key_spec.h b/src/lib/algo_base/key_spec.h new file mode 100644 index 000000000..15881c1a6 --- /dev/null +++ b/src/lib/algo_base/key_spec.h @@ -0,0 +1,95 @@ +/* +* Symmetric Key Length Specification +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KEY_LEN_SPECIFICATION_H__ +#define BOTAN_KEY_LEN_SPECIFICATION_H__ + +#include + +namespace Botan { + +/** +* Represents the length requirements on an algorithm key +*/ +class BOTAN_DLL Key_Length_Specification + { + public: + /** + * Constructor for fixed length keys + * @param keylen the supported key length + */ + Key_Length_Specification(size_t keylen) : + min_keylen(keylen), + max_keylen(keylen), + keylen_mod(1) + { + } + + /** + * Constructor for variable length keys + * @param min_k the smallest supported key length + * @param max_k the largest supported key length + * @param k_mod the number of bytes the key must be a multiple of + */ + Key_Length_Specification(size_t min_k, + size_t max_k, + size_t k_mod = 1) : + min_keylen(min_k), + max_keylen(max_k ? max_k : min_k), + keylen_mod(k_mod) + { + } + + /** + * @param length is a key length in bytes + * @return true iff this length is a valid length for this algo + */ + bool valid_keylength(size_t length) const + { + return ((length >= min_keylen) && + (length <= max_keylen) && + (length % keylen_mod == 0)); + } + + /** + * @return minimum key length in bytes + */ + size_t minimum_keylength() const + { + return min_keylen; + } + + /** + * @return maximum key length in bytes + */ + size_t maximum_keylength() const + { + return max_keylen; + } + + /** + * @return key length multiple in bytes + */ + size_t keylength_multiple() const + { + return keylen_mod; + } + + Key_Length_Specification multiple(size_t n) const + { + return Key_Length_Specification(n * min_keylen, + n * max_keylen, + n * keylen_mod); + } + + private: + size_t min_keylen, max_keylen, keylen_mod; + }; + +} + +#endif diff --git a/src/lib/algo_base/scan_name.cpp b/src/lib/algo_base/scan_name.cpp new file mode 100644 index 000000000..84a5e24b4 --- /dev/null +++ b/src/lib/algo_base/scan_name.cpp @@ -0,0 +1,222 @@ +/* +* SCAN Name Abstraction +* (C) 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string make_arg( + const std::vector >& name, size_t start) + { + std::string output = name[start].second; + size_t level = name[start].first; + + size_t paren_depth = 0; + + for(size_t i = start + 1; i != name.size(); ++i) + { + if(name[i].first <= name[start].first) + break; + + if(name[i].first > level) + { + output += '(' + name[i].second; + ++paren_depth; + } + else if(name[i].first < level) + { + output += ")," + name[i].second; + --paren_depth; + } + else + { + if(output[output.size() - 1] != '(') + output += ","; + output += name[i].second; + } + + level = name[i].first; + } + + for(size_t i = 0; i != paren_depth; ++i) + output += ')'; + + return output; + } + +std::pair +deref_aliases(const std::pair& in) + { + return std::make_pair(in.first, + SCAN_Name::deref_alias(in.second)); + } + +} + +std::mutex SCAN_Name::s_alias_map_mutex; +std::map SCAN_Name::s_alias_map; + +SCAN_Name::SCAN_Name(std::string algo_spec) + { + orig_algo_spec = algo_spec; + + std::vector > name; + size_t level = 0; + std::pair accum = std::make_pair(level, ""); + + std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; + + algo_spec = SCAN_Name::deref_alias(algo_spec); + + for(size_t i = 0; i != algo_spec.size(); ++i) + { + char c = algo_spec[i]; + + if(c == '/' || c == ',' || c == '(' || c == ')') + { + if(c == '(') + ++level; + else if(c == ')') + { + if(level == 0) + throw Decoding_Error(decoding_error + "Mismatched parens"); + --level; + } + + if(c == '/' && level > 0) + accum.second.push_back(c); + else + { + if(accum.second != "") + name.push_back(deref_aliases(accum)); + accum = std::make_pair(level, ""); + } + } + else + accum.second.push_back(c); + } + + if(accum.second != "") + name.push_back(deref_aliases(accum)); + + if(level != 0) + throw Decoding_Error(decoding_error + "Missing close paren"); + + if(name.size() == 0) + throw Decoding_Error(decoding_error + "Empty name"); + + alg_name = name[0].second; + + bool in_modes = false; + + for(size_t i = 1; i != name.size(); ++i) + { + if(name[i].first == 0) + { + mode_info.push_back(make_arg(name, i)); + in_modes = true; + } + else if(name[i].first == 1 && !in_modes) + args.push_back(make_arg(name, i)); + } + } + +std::string SCAN_Name::algo_name_and_args() const + { + std::string out; + + out = algo_name(); + + if(arg_count()) + { + out += '('; + for(size_t i = 0; i != arg_count(); ++i) + { + out += arg(i); + if(i != arg_count() - 1) + out += ','; + } + out += ')'; + + } + + return out; + } + +std::string SCAN_Name::arg(size_t i) const + { + if(i >= arg_count()) + throw std::range_error("SCAN_Name::argument - i out of range"); + return args[i]; + } + +std::string SCAN_Name::arg(size_t i, const std::string& def_value) const + { + if(i >= arg_count()) + return def_value; + return args[i]; + } + +size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const + { + if(i >= arg_count()) + return def_value; + return to_u32bit(args[i]); + } + +void SCAN_Name::add_alias(const std::string& alias, const std::string& basename) + { + std::lock_guard lock(s_alias_map_mutex); + + if(s_alias_map.find(alias) == s_alias_map.end()) + s_alias_map[alias] = basename; + } + +std::string SCAN_Name::deref_alias(const std::string& alias) + { + std::lock_guard lock(s_alias_map_mutex); + + std::string name = alias; + + for(auto i = s_alias_map.find(name); i != s_alias_map.end(); i = s_alias_map.find(name)) + name = i->second; + + return name; + } + +void SCAN_Name::set_default_aliases() + { + // common variations worth supporting + SCAN_Name::add_alias("EME-PKCS1-v1_5", "PKCS1v15"); + SCAN_Name::add_alias("3DES", "TripleDES"); + SCAN_Name::add_alias("DES-EDE", "TripleDES"); + SCAN_Name::add_alias("CAST5", "CAST-128"); + SCAN_Name::add_alias("SHA1", "SHA-160"); + SCAN_Name::add_alias("SHA-1", "SHA-160"); + SCAN_Name::add_alias("MARK-4", "RC4(256)"); + SCAN_Name::add_alias("ARC4", "RC4"); + SCAN_Name::add_alias("OMAC", "CMAC"); + + // should be renamed in sources + SCAN_Name::add_alias("OAEP-MGF1", "EME1"); + SCAN_Name::add_alias("EME-OAEP", "EME1"); + SCAN_Name::add_alias("X9.31", "EMSA2"); + SCAN_Name::add_alias("EMSA-PKCS1-v1_5", "EMSA3"); + SCAN_Name::add_alias("PSS-MGF1", "EMSA4"); + SCAN_Name::add_alias("EMSA-PSS", "EMSA4"); + + // probably can be removed + SCAN_Name::add_alias("GOST", "GOST-28147-89"); + SCAN_Name::add_alias("GOST-34.11", "GOST-R-34.11-94"); + } + +} diff --git a/src/lib/algo_base/scan_name.h b/src/lib/algo_base/scan_name.h new file mode 100644 index 000000000..f4c4b46e7 --- /dev/null +++ b/src/lib/algo_base/scan_name.h @@ -0,0 +1,108 @@ +/* +* SCAN Name Abstraction +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SCAN_NAME_H__ +#define BOTAN_SCAN_NAME_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +A class encapsulating a SCAN name (similar to JCE conventions) +http://www.users.zetnet.co.uk/hopwood/crypto/scan/ +*/ +class BOTAN_DLL SCAN_Name + { + public: + /** + * @param algo_spec A SCAN-format name + */ + SCAN_Name(std::string algo_spec); + + /** + * @return original input string + */ + std::string as_string() const { return orig_algo_spec; } + + /** + * @return algorithm name + */ + std::string algo_name() const { return alg_name; } + + /** + * @return algorithm name plus any arguments + */ + std::string algo_name_and_args() const; + + /** + * @return number of arguments + */ + size_t arg_count() const { return args.size(); } + + /** + * @param lower is the lower bound + * @param upper is the upper bound + * @return if the number of arguments is between lower and upper + */ + bool arg_count_between(size_t lower, size_t upper) const + { return ((arg_count() >= lower) && (arg_count() <= upper)); } + + /** + * @param i which argument + * @return ith argument + */ + std::string arg(size_t i) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument or the default value + */ + std::string arg(size_t i, const std::string& def_value) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument as an integer, or the default value + */ + size_t arg_as_integer(size_t i, size_t def_value) const; + + /** + * @return cipher mode (if any) + */ + std::string cipher_mode() const + { return (mode_info.size() >= 1) ? mode_info[0] : ""; } + + /** + * @return cipher mode padding (if any) + */ + std::string cipher_mode_pad() const + { return (mode_info.size() >= 2) ? mode_info[1] : ""; } + + static void add_alias(const std::string& alias, const std::string& basename); + + static std::string deref_alias(const std::string& alias); + + static void set_default_aliases(); + private: + static std::mutex s_alias_map_mutex; + static std::map s_alias_map; + + std::string orig_algo_spec; + std::string alg_name; + std::vector args; + std::vector mode_info; + }; + +} + +#endif diff --git a/src/lib/algo_base/sym_algo.h b/src/lib/algo_base/sym_algo.h new file mode 100644 index 000000000..c937d08ff --- /dev/null +++ b/src/lib/algo_base/sym_algo.h @@ -0,0 +1,97 @@ +/* +* Symmetric Algorithm Base Class +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SYMMETRIC_ALGORITHM_H__ +#define BOTAN_SYMMETRIC_ALGORITHM_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents a symmetric algorithm object. +*/ +class BOTAN_DLL SymmetricAlgorithm : public Algorithm + { + public: + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * @return minimum allowed key length + */ + size_t maximum_keylength() const + { + return key_spec().maximum_keylength(); + } + + /** + * @return maxmium allowed key length + */ + size_t minimum_keylength() const + { + return key_spec().minimum_keylength(); + } + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this object. + * @param key the SymmetricKey to be set. + */ + void set_key(const SymmetricKey& key) + { set_key(key.begin(), key.length()); } + + /** + * Set the symmetric key of this object. + * @param key the to be set as a byte array. + * @param length in bytes of key param + */ + void set_key(const byte key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + + template + void set_key(const std::vector& v) + { + set_key(&v[0], v.size()); + } + private: + /** + * Run the key schedule + * @param key the key + * @param length of key + */ + virtual void key_schedule(const byte key[], size_t length) = 0; + }; + +/** +* The two possible directions for cipher filters, determining whether they +* actually perform encryption or decryption. +*/ +enum Cipher_Dir { ENCRYPTION, DECRYPTION }; + +} + +#endif diff --git a/src/lib/algo_base/symkey.cpp b/src/lib/algo_base/symkey.cpp new file mode 100644 index 000000000..52b216361 --- /dev/null +++ b/src/lib/algo_base/symkey.cpp @@ -0,0 +1,133 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an OctetString from RNG output +*/ +OctetString::OctetString(RandomNumberGenerator& rng, + size_t length) + { + bits = rng.random_vec(length); + } + +/* +* Create an OctetString from a hex string +*/ +OctetString::OctetString(const std::string& hex_string) + { + bits.resize(1 + hex_string.length() / 2); + bits.resize(hex_decode(&bits[0], hex_string)); + } + +/* +* Create an OctetString from a byte string +*/ +OctetString::OctetString(const byte in[], size_t n) + { + bits.assign(in, in + n); + } + +/* +* Set the parity of each key byte to odd +*/ +void OctetString::set_odd_parity() + { + const byte ODD_PARITY[256] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, + 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, + 0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52, + 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, + 0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83, + 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, + 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, + 0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, + 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3, + 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, + 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, + 0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, + 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3, + 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, + 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, + 0xFD, 0xFD, 0xFE, 0xFE }; + + for(size_t j = 0; j != bits.size(); ++j) + bits[j] = ODD_PARITY[bits[j]]; + } + +/* +* Hex encode an OctetString +*/ +std::string OctetString::as_string() const + { + return hex_encode(&bits[0], bits.size()); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString& OctetString::operator^=(const OctetString& k) + { + if(&k == this) { zeroise(bits); return (*this); } + xor_buf(&bits[0], k.begin(), std::min(length(), k.length())); + return (*this); + } + +/* +* Equality Operation for OctetStrings +*/ +bool operator==(const OctetString& s1, const OctetString& s2) + { + return (s1.bits_of() == s2.bits_of()); + } + +/* +* Unequality Operation for OctetStrings +*/ +bool operator!=(const OctetString& s1, const OctetString& s2) + { + return !(s1 == s2); + } + +/* +* Append Operation for OctetStrings +*/ +OctetString operator+(const OctetString& k1, const OctetString& k2) + { + secure_vector out; + out += k1.bits_of(); + out += k2.bits_of(); + return OctetString(out); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString operator^(const OctetString& k1, const OctetString& k2) + { + secure_vector ret(std::max(k1.length(), k2.length())); + + copy_mem(&ret[0], k1.begin(), k1.length()); + xor_buf(&ret[0], k2.begin(), k2.length()); + return OctetString(ret); + } + +} diff --git a/src/lib/algo_base/symkey.h b/src/lib/algo_base/symkey.h new file mode 100644 index 000000000..b47da8a69 --- /dev/null +++ b/src/lib/algo_base/symkey.h @@ -0,0 +1,143 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SYMKEY_H__ +#define BOTAN_SYMKEY_H__ + +#include +#include + +namespace Botan { + +/** +* Octet String +*/ +class BOTAN_DLL OctetString + { + public: + /** + * @return size of this octet string in bytes + */ + size_t length() const { return bits.size(); } + + /** + * @return this object as a secure_vector + */ + secure_vector bits_of() const { return bits; } + + /** + * @return start of this string + */ + const byte* begin() const { return &bits[0]; } + + /** + * @return end of this string + */ + const byte* end() const { return &bits[bits.size()]; } + + /** + * @return this encoded as hex + */ + std::string as_string() const; + + /** + * XOR the contents of another octet string into this one + * @param other octet string + * @return reference to this + */ + OctetString& operator^=(const OctetString& other); + + /** + * Force to have odd parity + */ + void set_odd_parity(); + + /** + * Create a new OctetString + * @param str is a hex encoded string + */ + OctetString(const std::string& str = ""); + + /** + * Create a new random OctetString + * @param rng is a random number generator + * @param len is the desired length in bytes + */ + OctetString(class RandomNumberGenerator& rng, size_t len); + + /** + * Create a new OctetString + * @param in is an array + * @param len is the length of in in bytes + */ + OctetString(const byte in[], size_t len); + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const secure_vector& in) : bits(in) {} + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const std::vector& in) : bits(&in[0], &in[in.size()]) {} + private: + secure_vector bits; + }; + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is equal to y +*/ +BOTAN_DLL bool operator==(const OctetString& x, + const OctetString& y); + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is not equal to y +*/ +BOTAN_DLL bool operator!=(const OctetString& x, + const OctetString& y); + +/** +* Concatenate two strings +* @param x an octet string +* @param y an octet string +* @return x concatenated with y +*/ +BOTAN_DLL OctetString operator+(const OctetString& x, + const OctetString& y); + +/** +* XOR two strings +* @param x an octet string +* @param y an octet string +* @return x XORed with y +*/ +BOTAN_DLL OctetString operator^(const OctetString& x, + const OctetString& y); + + +/** +* Alternate name for octet string showing intent to use as a key +*/ +typedef OctetString SymmetricKey; + +/** +* Alternate name for octet string showing intent to use as an IV +*/ +typedef OctetString InitializationVector; + +} + +#endif diff --git a/src/lib/algo_base/transform.h b/src/lib/algo_base/transform.h new file mode 100644 index 000000000..2eec9d85b --- /dev/null +++ b/src/lib/algo_base/transform.h @@ -0,0 +1,99 @@ +/* +* Transformations of data +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TRANSFORM_H__ +#define BOTAN_TRANSFORM_H__ + +#include +#include + +namespace Botan { + +/** +* Interface for general transformations on data +*/ +class BOTAN_DLL Transformation : public SymmetricAlgorithm + { + public: + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template + secure_vector start_vec(const std::vector& nonce) + { + return start(&nonce[0], nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + virtual secure_vector start(const byte nonce[], size_t nonce_len) = 0; + + /** + * Process some data. Input must be in size update_granularity() byte blocks. + * @param blocks in/out paramter which will possibly be resized + */ + virtual void update(secure_vector& blocks, size_t offset = 0) = 0; + + /** + * Complete processing of a message. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector& final_block, size_t offset = 0) = 0; + + /** + * Returns the size of the output if this transform is used to process a + * message with input_length bytes. Will throw if unable to give a precise + * answer. + */ + virtual size_t output_length(size_t input_length) const = 0; + + /** + * @return size of required blocks to update + */ + virtual size_t update_granularity() const = 0; + + /** + * @return required minimium size to finalize() - may be any + * length larger than this. + */ + virtual size_t minimum_final_size() const = 0; + + /** + * Return the default size for a nonce + */ + virtual size_t default_nonce_length() const = 0; + + BOTAN_DEPRECATED("Use default_nonce_length") + size_t default_nonce_size() const + { return default_nonce_length(); } + + /** + * Return true iff nonce_len is a valid length for the nonce + */ + virtual bool valid_nonce_length(size_t nonce_len) const = 0; + + /** + * Return some short name describing the provider of this tranformation. + * Useful in cases where multiple implementations are available (eg, + * different implementations of AES). Default "core" is used for the + * 'standard' implementation included in the library. + */ + virtual std::string provider() const { return "core"; } + + virtual ~Transformation() {} + }; + +} + +#endif diff --git a/src/lib/algo_factory/algo_cache.h b/src/lib/algo_factory/algo_cache.h new file mode 100644 index 000000000..3bd9f0031 --- /dev/null +++ b/src/lib/algo_factory/algo_cache.h @@ -0,0 +1,239 @@ +/* +* An algorithm cache (used by Algorithm_Factory) +* (C) 2008-2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ALGORITHM_CACHE_TEMPLATE_H__ +#define BOTAN_ALGORITHM_CACHE_TEMPLATE_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* @param prov_name a provider name +* @return weight for this provider +*/ +size_t static_provider_weight(const std::string& prov_name); + +/** +* Algorithm_Cache (used by Algorithm_Factory) +*/ +template +class Algorithm_Cache + { + public: + /** + * @param algo_spec names the requested algorithm + * @param pref_provider suggests a preferred provider + * @return prototype object, or NULL + */ + const T* get(const std::string& algo_spec, + const std::string& pref_provider); + + /** + * Add a new algorithm implementation to the cache + * @param algo the algorithm prototype object + * @param requested_name how this name will be requested + * @param provider_name is the name of the provider of this prototype + */ + void add(T* algo, + const std::string& requested_name, + const std::string& provider_name); + + /** + * Set the preferred provider + * @param algo_spec names the algorithm + * @param provider names the preferred provider + */ + void set_preferred_provider(const std::string& algo_spec, + const std::string& provider); + + /** + * Return the list of providers of this algorithm + * @param algo_name names the algorithm + * @return list of providers of this algorithm + */ + std::vector providers_of(const std::string& algo_name); + + /** + * Clear the cache + */ + void clear_cache(); + + ~Algorithm_Cache() { clear_cache(); } + private: + typename std::map >::const_iterator + find_algorithm(const std::string& algo_spec); + + std::mutex mutex; + std::map aliases; + std::map pref_providers; + std::map > algorithms; + }; + +/* +* Look for an algorithm implementation in the cache, also checking aliases +* Assumes object lock is held +*/ +template +typename std::map >::const_iterator +Algorithm_Cache::find_algorithm(const std::string& algo_spec) + { + auto algo = algorithms.find(algo_spec); + + // Not found? Check if a known alias + if(algo == algorithms.end()) + { + auto alias = aliases.find(algo_spec); + + if(alias != aliases.end()) + algo = algorithms.find(alias->second); + } + + return algo; + } + +/* +* Look for an algorithm implementation by a particular provider +*/ +template +const T* Algorithm_Cache::get(const std::string& algo_spec, + const std::string& requested_provider) + { + std::lock_guard lock(mutex); + + auto algo = find_algorithm(algo_spec); + if(algo == algorithms.end()) // algo not found at all (no providers) + return nullptr; + + // If a provider is requested specifically, return it or fail entirely + if(requested_provider != "") + { + auto prov = algo->second.find(requested_provider); + if(prov != algo->second.end()) + return prov->second; + return nullptr; + } + + const T* prototype = nullptr; + std::string prototype_provider; + size_t prototype_prov_weight = 0; + + const std::string pref_provider = search_map(pref_providers, algo_spec); + + for(auto i = algo->second.begin(); i != algo->second.end(); ++i) + { + // preferred prov exists, return immediately + if(i->first == pref_provider) + return i->second; + + const size_t prov_weight = static_provider_weight(i->first); + + if(prototype == nullptr || prov_weight > prototype_prov_weight) + { + prototype = i->second; + prototype_provider = i->first; + prototype_prov_weight = prov_weight; + } + } + + return prototype; + } + +/* +* Add an implementation to the cache +*/ +template +void Algorithm_Cache::add(T* algo, + const std::string& requested_name, + const std::string& provider) + { + if(!algo) + return; + + std::lock_guard lock(mutex); + + if(algo->name() != requested_name && + aliases.find(requested_name) == aliases.end()) + { + aliases[requested_name] = algo->name(); + } + + if(!algorithms[algo->name()][provider]) + algorithms[algo->name()][provider] = algo; + else + delete algo; + } + +/* +* Find the providers of this algo (if any) +*/ +template std::vector +Algorithm_Cache::providers_of(const std::string& algo_name) + { + std::lock_guard lock(mutex); + + std::vector providers; + + auto algo = find_algorithm(algo_name); + if(algo != algorithms.end()) + { + auto provider = algo->second.begin(); + + while(provider != algo->second.end()) + { + providers.push_back(provider->first); + ++provider; + } + } + + return providers; + } + +/* +* Set the preferred provider for an algorithm +*/ +template +void Algorithm_Cache::set_preferred_provider(const std::string& algo_spec, + const std::string& provider) + { + std::lock_guard lock(mutex); + + pref_providers[algo_spec] = provider; + } + +/* +* Clear out the cache +*/ +template +void Algorithm_Cache::clear_cache() + { + auto algo = algorithms.begin(); + + while(algo != algorithms.end()) + { + auto provider = algo->second.begin(); + + while(provider != algo->second.end()) + { + delete provider->second; + ++provider; + } + + ++algo; + } + + algorithms.clear(); + } + +} + +#endif diff --git a/src/lib/algo_factory/algo_factory.cpp b/src/lib/algo_factory/algo_factory.cpp new file mode 100644 index 000000000..1683648bd --- /dev/null +++ b/src/lib/algo_factory/algo_factory.cpp @@ -0,0 +1,352 @@ +/* +* Algorithm Factory +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace Botan { + +namespace { + +/* +* Template functions for the factory prototype/search algorithm +*/ +template +T* engine_get_algo(Engine*, + const SCAN_Name&, + Algorithm_Factory&) + { return nullptr; } + +template<> +BlockCipher* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_block_cipher(request, af); } + +template<> +StreamCipher* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_stream_cipher(request, af); } + +template<> +HashFunction* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_hash(request, af); } + +template<> +MessageAuthenticationCode* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_mac(request, af); } + +template<> +PBKDF* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_pbkdf(request, af); } + +template +const T* factory_prototype(const std::string& algo_spec, + const std::string& provider, + const std::vector& engines, + Algorithm_Factory& af, + Algorithm_Cache* cache) + { + if(const T* cache_hit = cache->get(algo_spec, provider)) + return cache_hit; + + SCAN_Name scan_name(algo_spec); + + if(scan_name.cipher_mode() != "") + return nullptr; + + for(size_t i = 0; i != engines.size(); ++i) + { + if(provider == "" || engines[i]->provider_name() == provider) + { + if(T* impl = engine_get_algo(engines[i], scan_name, af)) + cache->add(impl, algo_spec, engines[i]->provider_name()); + } + } + + return cache->get(algo_spec, provider); + } + +} + +/* +* Setup caches +*/ +Algorithm_Factory::Algorithm_Factory() + { + block_cipher_cache = new Algorithm_Cache(); + stream_cipher_cache = new Algorithm_Cache(); + hash_cache = new Algorithm_Cache(); + mac_cache = new Algorithm_Cache(); + pbkdf_cache = new Algorithm_Cache(); + } + +/* +* Delete all engines +*/ +Algorithm_Factory::~Algorithm_Factory() + { + delete block_cipher_cache; + delete stream_cipher_cache; + delete hash_cache; + delete mac_cache; + delete pbkdf_cache; + + for(auto i = engines.begin(); i != engines.end(); ++i) + delete *i; + } + +void Algorithm_Factory::clear_caches() + { + block_cipher_cache->clear_cache(); + stream_cipher_cache->clear_cache(); + hash_cache->clear_cache(); + mac_cache->clear_cache(); + pbkdf_cache->clear_cache(); + } + +void Algorithm_Factory::add_engine(Engine* engine) + { + clear_caches(); + engines.push_back(engine); + } + +/* +* Set the preferred provider for an algorithm +*/ +void Algorithm_Factory::set_preferred_provider(const std::string& algo_spec, + const std::string& provider) + { + if(prototype_block_cipher(algo_spec)) + block_cipher_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_stream_cipher(algo_spec)) + stream_cipher_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_hash_function(algo_spec)) + hash_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_mac(algo_spec)) + mac_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_pbkdf(algo_spec)) + pbkdf_cache->set_preferred_provider(algo_spec, provider); + } + +/* +* Get an engine out of the list +*/ +Engine* Algorithm_Factory::get_engine_n(size_t n) const + { + if(n >= engines.size()) + return nullptr; + return engines[n]; + } + +/* +* Return the possible providers of a request +* Note: assumes you don't have different types by the same name +*/ +std::vector +Algorithm_Factory::providers_of(const std::string& algo_spec) + { + /* The checks with if(prototype_X(algo_spec)) have the effect of + forcing a full search, since otherwise there might not be any + providers at all in the cache. + */ + + if(prototype_block_cipher(algo_spec)) + return block_cipher_cache->providers_of(algo_spec); + else if(prototype_stream_cipher(algo_spec)) + return stream_cipher_cache->providers_of(algo_spec); + else if(prototype_hash_function(algo_spec)) + return hash_cache->providers_of(algo_spec); + else if(prototype_mac(algo_spec)) + return mac_cache->providers_of(algo_spec); + else if(prototype_pbkdf(algo_spec)) + return pbkdf_cache->providers_of(algo_spec); + else + return std::vector(); + } + +/* +* Return the prototypical block cipher corresponding to this request +*/ +const BlockCipher* +Algorithm_Factory::prototype_block_cipher(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, engines, + *this, block_cipher_cache); + } + +/* +* Return the prototypical stream cipher corresponding to this request +*/ +const StreamCipher* +Algorithm_Factory::prototype_stream_cipher(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, engines, + *this, stream_cipher_cache); + } + +/* +* Return the prototypical object corresponding to this request (if found) +*/ +const HashFunction* +Algorithm_Factory::prototype_hash_function(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, engines, + *this, hash_cache); + } + +/* +* Return the prototypical object corresponding to this request +*/ +const MessageAuthenticationCode* +Algorithm_Factory::prototype_mac(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, + engines, + *this, mac_cache); + } + +/* +* Return the prototypical object corresponding to this request +*/ +const PBKDF* +Algorithm_Factory::prototype_pbkdf(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, + engines, + *this, pbkdf_cache); + } + +/* +* Return a new block cipher corresponding to this request +*/ +BlockCipher* +Algorithm_Factory::make_block_cipher(const std::string& algo_spec, + const std::string& provider) + { + if(const BlockCipher* proto = prototype_block_cipher(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new stream cipher corresponding to this request +*/ +StreamCipher* +Algorithm_Factory::make_stream_cipher(const std::string& algo_spec, + const std::string& provider) + { + if(const StreamCipher* proto = prototype_stream_cipher(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new object corresponding to this request +*/ +HashFunction* +Algorithm_Factory::make_hash_function(const std::string& algo_spec, + const std::string& provider) + { + if(const HashFunction* proto = prototype_hash_function(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new object corresponding to this request +*/ +MessageAuthenticationCode* +Algorithm_Factory::make_mac(const std::string& algo_spec, + const std::string& provider) + { + if(const MessageAuthenticationCode* proto = prototype_mac(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new object corresponding to this request +*/ +PBKDF* +Algorithm_Factory::make_pbkdf(const std::string& algo_spec, + const std::string& provider) + { + if(const PBKDF* proto = prototype_pbkdf(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Add a new block cipher +*/ +void Algorithm_Factory::add_block_cipher(BlockCipher* block_cipher, + const std::string& provider) + { + block_cipher_cache->add(block_cipher, block_cipher->name(), provider); + } + +/* +* Add a new stream cipher +*/ +void Algorithm_Factory::add_stream_cipher(StreamCipher* stream_cipher, + const std::string& provider) + { + stream_cipher_cache->add(stream_cipher, stream_cipher->name(), provider); + } + +/* +* Add a new hash +*/ +void Algorithm_Factory::add_hash_function(HashFunction* hash, + const std::string& provider) + { + hash_cache->add(hash, hash->name(), provider); + } + +/* +* Add a new mac +*/ +void Algorithm_Factory::add_mac(MessageAuthenticationCode* mac, + const std::string& provider) + { + mac_cache->add(mac, mac->name(), provider); + } + +/* +* Add a new PBKDF +*/ +void Algorithm_Factory::add_pbkdf(PBKDF* pbkdf, + const std::string& provider) + { + pbkdf_cache->add(pbkdf, pbkdf->name(), provider); + } + +} diff --git a/src/lib/algo_factory/algo_factory.h b/src/lib/algo_factory/algo_factory.h new file mode 100644 index 000000000..201982766 --- /dev/null +++ b/src/lib/algo_factory/algo_factory.h @@ -0,0 +1,225 @@ +/* +* Algorithm Factory +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ALGORITHM_FACTORY_H__ +#define BOTAN_ALGORITHM_FACTORY_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Forward declarations (don't need full definitions here) +*/ +class BlockCipher; +class StreamCipher; +class HashFunction; +class MessageAuthenticationCode; +class PBKDF; + +template class Algorithm_Cache; + +class Engine; + +/** +* Algorithm Factory +*/ +class BOTAN_DLL Algorithm_Factory + { + public: + /** + * Constructor + */ + Algorithm_Factory(); + + /** + * Destructor + */ + ~Algorithm_Factory(); + + /** + * @param engine to add (Algorithm_Factory takes ownership) + */ + void add_engine(Engine* engine); + + /** + * Clear out any cached objects + */ + void clear_caches(); + + /** + * @param algo_spec the algorithm we are querying + * @returns list of providers of this algorithm + */ + std::vector providers_of(const std::string& algo_spec); + + /** + * @param algo_spec the algorithm we are setting a provider for + * @param provider the provider we would like to use + */ + void set_preferred_provider(const std::string& algo_spec, + const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const BlockCipher* + prototype_block_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + BlockCipher* make_block_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_block_cipher(BlockCipher* algo, const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const StreamCipher* + prototype_stream_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + StreamCipher* make_stream_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_stream_cipher(StreamCipher* algo, const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const HashFunction* + prototype_hash_function(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + HashFunction* make_hash_function(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_hash_function(HashFunction* algo, const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const MessageAuthenticationCode* + prototype_mac(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + MessageAuthenticationCode* make_mac(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_mac(MessageAuthenticationCode* algo, + const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const PBKDF* prototype_pbkdf(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + PBKDF* make_pbkdf(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_pbkdf(PBKDF* algo, const std::string& provider); + + /** + * An iterator for the engines in this factory + * @deprecated Avoid in new code + */ + class BOTAN_DLL Engine_Iterator + { + public: + /** + * @return next engine in the sequence + */ + Engine* next() { return af.get_engine_n(n++); } + + /** + * @param a an algorithm factory + */ + Engine_Iterator(const Algorithm_Factory& a) : + af(a) { n = 0; } + private: + const Algorithm_Factory& af; + size_t n; + }; + friend class Engine_Iterator; + + private: + Algorithm_Factory(const Algorithm_Factory&) {} + Algorithm_Factory& operator=(const Algorithm_Factory&) + { return (*this); } + + Engine* get_engine_n(size_t n) const; + + std::vector engines; + + Algorithm_Cache* block_cipher_cache; + Algorithm_Cache* stream_cipher_cache; + Algorithm_Cache* hash_cache; + Algorithm_Cache* mac_cache; + Algorithm_Cache* pbkdf_cache; + }; + +} + +#endif diff --git a/src/lib/algo_factory/info.txt b/src/lib/algo_factory/info.txt new file mode 100644 index 000000000..837ced1d0 --- /dev/null +++ b/src/lib/algo_factory/info.txt @@ -0,0 +1,24 @@ +load_on auto + +define ALGORITHM_FACTORY 20131128 + + +algo_factory.h + + + +algo_cache.h + + + +algo_factory.cpp +prov_weight.cpp + + + +block +engine +hash +mac +stream + diff --git a/src/lib/algo_factory/prov_weight.cpp b/src/lib/algo_factory/prov_weight.cpp new file mode 100644 index 000000000..fca791333 --- /dev/null +++ b/src/lib/algo_factory/prov_weight.cpp @@ -0,0 +1,34 @@ +/* +* Default provider weights for Algorithm_Cache +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/** +* Return a static provider weighing +*/ +size_t static_provider_weight(const std::string& prov_name) + { + /* + * Prefer asm over C++, but prefer anything over OpenSSL or GNU MP; to use + * them, set the provider explicitly for the algorithms you want + */ + + if(prov_name == "aes_isa") return 9; + if(prov_name == "simd") return 8; + if(prov_name == "asm") return 7; + + if(prov_name == "core") return 5; + + if(prov_name == "openssl") return 2; + if(prov_name == "gmp") return 1; + + return 0; // other/unknown + } + +} diff --git a/src/lib/alloc/info.txt b/src/lib/alloc/info.txt new file mode 100644 index 000000000..0ab7fa768 --- /dev/null +++ b/src/lib/alloc/info.txt @@ -0,0 +1,3 @@ + +secmem.h + diff --git a/src/lib/alloc/locking_allocator/info.txt b/src/lib/alloc/locking_allocator/info.txt new file mode 100644 index 000000000..09b59406c --- /dev/null +++ b/src/lib/alloc/locking_allocator/info.txt @@ -0,0 +1,9 @@ +define LOCKING_ALLOCATOR 20131128 + + +linux +freebsd +netbsd +openbsd +solaris + diff --git a/src/lib/alloc/locking_allocator/locking_allocator.cpp b/src/lib/alloc/locking_allocator/locking_allocator.cpp new file mode 100644 index 000000000..13effbb09 --- /dev/null +++ b/src/lib/alloc/locking_allocator/locking_allocator.cpp @@ -0,0 +1,262 @@ +/* +* Mlock Allocator +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +size_t mlock_limit() + { + /* + * Linux defaults to only 64 KiB of mlockable memory per process + * (too small) but BSDs offer a small fraction of total RAM (more + * than we need). Bound the total mlock size to 512 KiB which is + * enough to run the entire test suite without spilling to non-mlock + * memory (and thus presumably also enough for many useful + * programs), but small enough that we should not cause problems + * even if many processes are mlocking on the same machine. + */ + const size_t MLOCK_UPPER_BOUND = 512*1024; + + struct rlimit limits; + ::getrlimit(RLIMIT_MEMLOCK, &limits); + + if(limits.rlim_cur < limits.rlim_max) + { + limits.rlim_cur = limits.rlim_max; + ::setrlimit(RLIMIT_MEMLOCK, &limits); + ::getrlimit(RLIMIT_MEMLOCK, &limits); + } + + return std::min(limits.rlim_cur, MLOCK_UPPER_BOUND); + } + +bool ptr_in_pool(const void* pool_ptr, size_t poolsize, + const void* buf_ptr, size_t bufsize) + { + const uintptr_t pool = reinterpret_cast(pool_ptr); + const uintptr_t buf = reinterpret_cast(buf_ptr); + + if(buf < pool || buf >= pool + poolsize) + return false; + + BOTAN_ASSERT(buf + bufsize <= pool + poolsize, + "Pointer does not partially overlap pool"); + + return true; + } + +size_t padding_for_alignment(size_t offset, size_t desired_alignment) + { + size_t mod = offset % desired_alignment; + if(mod == 0) + return 0; // already right on + return desired_alignment - mod; + } + +} + +void* mlock_allocator::allocate(size_t num_elems, size_t elem_size) + { + if(!m_pool) + return nullptr; + + const size_t n = num_elems * elem_size; + const size_t alignment = elem_size; + + if(n / elem_size != num_elems) + return nullptr; // overflow! + + if(n > m_poolsize || n > BOTAN_MLOCK_ALLOCATOR_MAX_ALLOCATION) + return nullptr; + + std::lock_guard lock(m_mutex); + + auto best_fit = m_freelist.end(); + + for(auto i = m_freelist.begin(); i != m_freelist.end(); ++i) + { + // If we have a perfect fit, use it immediately + if(i->second == n && (i->first % alignment) == 0) + { + const size_t offset = i->first; + m_freelist.erase(i); + clear_mem(m_pool + offset, n); + + BOTAN_ASSERT((reinterpret_cast(m_pool) + offset) % alignment == 0, + "Returning correctly aligned pointer"); + + return m_pool + offset; + } + + if((i->second >= (n + padding_for_alignment(i->first, alignment)) && + ((best_fit == m_freelist.end()) || (best_fit->second > i->second)))) + { + best_fit = i; + } + } + + if(best_fit != m_freelist.end()) + { + const size_t offset = best_fit->first; + + const size_t alignment_padding = padding_for_alignment(offset, alignment); + + best_fit->first += n + alignment_padding; + best_fit->second -= n + alignment_padding; + + // Need to realign, split the block + if(alignment_padding) + { + /* + If we used the entire block except for small piece used for + alignment at the beginning, so just update the entry already + in place (as it is in the correct location), rather than + deleting the empty range and inserting the new one in the + same location. + */ + if(best_fit->second == 0) + { + best_fit->first = offset; + best_fit->second = alignment_padding; + } + else + m_freelist.insert(best_fit, std::make_pair(offset, alignment_padding)); + } + + clear_mem(m_pool + offset + alignment_padding, n); + + BOTAN_ASSERT((reinterpret_cast(m_pool) + offset + alignment_padding) % alignment == 0, + "Returning correctly aligned pointer"); + + return m_pool + offset + alignment_padding; + } + + return nullptr; + } + +bool mlock_allocator::deallocate(void* p, size_t num_elems, size_t elem_size) + { + if(!m_pool) + return false; + + size_t n = num_elems * elem_size; + + /* + We return nullptr in allocate if there was an overflow, so we + should never ever see an overflow in a deallocation. + */ + BOTAN_ASSERT(n / elem_size == num_elems, + "No overflow in deallocation"); + + if(!ptr_in_pool(m_pool, m_poolsize, p, n)) + return false; + + std::lock_guard lock(m_mutex); + + const size_t start = static_cast(p) - m_pool; + + auto comp = [](std::pair x, std::pair y){ return x.first < y.first; }; + + auto i = std::lower_bound(m_freelist.begin(), m_freelist.end(), + std::make_pair(start, 0), comp); + + // try to merge with later block + if(i != m_freelist.end() && start + n == i->first) + { + i->first = start; + i->second += n; + n = 0; + } + + // try to merge with previous block + if(i != m_freelist.begin()) + { + auto prev = std::prev(i); + + if(prev->first + prev->second == start) + { + if(n) + { + prev->second += n; + n = 0; + } + else + { + // merge adjoining + prev->second += i->second; + m_freelist.erase(i); + } + } + } + + if(n != 0) // no merge possible? + m_freelist.insert(i, std::make_pair(start, n)); + + return true; + } + +mlock_allocator::mlock_allocator() : + m_poolsize(mlock_limit()), + m_pool(nullptr) + { +#if !defined(MAP_NOCORE) + #define MAP_NOCORE 0 +#endif + + if(m_poolsize) + { + m_pool = static_cast( + ::mmap( + nullptr, m_poolsize, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED | MAP_NOCORE, + -1, 0)); + + if(m_pool == static_cast(MAP_FAILED)) + { + m_pool = nullptr; + throw std::runtime_error("Failed to mmap locking_allocator pool"); + } + + clear_mem(m_pool, m_poolsize); + + if(::mlock(m_pool, m_poolsize) != 0) + { + ::munmap(m_pool, m_poolsize); + m_pool = nullptr; + throw std::runtime_error("Could not mlock " + std::to_string(m_poolsize) + " bytes"); + } + + m_freelist.push_back(std::make_pair(0, m_poolsize)); + } + } + +mlock_allocator::~mlock_allocator() + { + if(m_pool) + { + clear_mem(m_pool, m_poolsize); + ::munlock(m_pool, m_poolsize); + ::munmap(m_pool, m_poolsize); + m_pool = nullptr; + } + } + +mlock_allocator& mlock_allocator::instance() + { + static mlock_allocator mlock; + return mlock; + } + +} diff --git a/src/lib/alloc/locking_allocator/locking_allocator.h b/src/lib/alloc/locking_allocator/locking_allocator.h new file mode 100644 index 000000000..3bebea5f2 --- /dev/null +++ b/src/lib/alloc/locking_allocator/locking_allocator.h @@ -0,0 +1,44 @@ +/* +* Mlock Allocator +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MLOCK_ALLOCATOR_H__ +#define BOTAN_MLOCK_ALLOCATOR_H__ + +#include +#include +#include + +namespace Botan { + +class BOTAN_DLL mlock_allocator + { + public: + static mlock_allocator& instance(); + + void* allocate(size_t num_elems, size_t elem_size); + + bool deallocate(void* p, size_t num_elems, size_t elem_size); + + mlock_allocator(const mlock_allocator&) = delete; + + mlock_allocator& operator=(const mlock_allocator&) = delete; + + private: + mlock_allocator(); + + ~mlock_allocator(); + + const size_t m_poolsize; + + std::mutex m_mutex; + std::vector> m_freelist; + byte* m_pool; + }; + +} + +#endif diff --git a/src/lib/alloc/secmem.h b/src/lib/alloc/secmem.h new file mode 100644 index 000000000..2f4d65f33 --- /dev/null +++ b/src/lib/alloc/secmem.h @@ -0,0 +1,185 @@ +/* +* Secure Memory Buffers +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__ +#define BOTAN_SECURE_MEMORY_BUFFERS_H__ + +#include +#include +#include + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + #include +#endif + +namespace Botan { + +template +class secure_allocator + { + public: + typedef T value_type; + + typedef T* pointer; + typedef const T* const_pointer; + + typedef T& reference; + typedef const T& const_reference; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + secure_allocator() noexcept {} + + ~secure_allocator() noexcept {} + + pointer address(reference x) const noexcept + { return std::addressof(x); } + + const_pointer address(const_reference x) const noexcept + { return std::addressof(x); } + + pointer allocate(size_type n, const void* = 0) + { +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(pointer p = static_cast(mlock_allocator::instance().allocate(n, sizeof(T)))) + return p; +#endif + + pointer p = new T[n]; + clear_mem(p, n); + return p; + } + + void deallocate(pointer p, size_type n) + { + clear_mem(p, n); + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(mlock_allocator::instance().deallocate(p, n, sizeof(T))) + return; +#endif + + delete [] p; + } + + size_type max_size() const noexcept + { + return static_cast(-1) / sizeof(T); + } + + template + void construct(U* p, Args&&... args) + { + ::new(static_cast(p)) U(std::forward(args)...); + } + + template void destroy(U* p) { p->~U(); } + }; + +template inline bool +operator==(const secure_allocator&, const secure_allocator&) + { return true; } + +template inline bool +operator!=(const secure_allocator&, const secure_allocator&) + { return false; } + +template using secure_vector = std::vector>; + +template +std::vector unlock(const secure_vector& in) + { + std::vector out(in.size()); + copy_mem(&out[0], &in[0], in.size()); + return out; + } + +template +size_t buffer_insert(std::vector& buf, + size_t buf_offset, + const T input[], + size_t input_length) + { + const size_t to_copy = std::min(input_length, buf.size() - buf_offset); + copy_mem(&buf[buf_offset], input, to_copy); + return to_copy; + } + +template +size_t buffer_insert(std::vector& buf, + size_t buf_offset, + const std::vector& input) + { + const size_t to_copy = std::min(input.size(), buf.size() - buf_offset); + copy_mem(&buf[buf_offset], &input[0], to_copy); + return to_copy; + } + +template +std::vector& +operator+=(std::vector& out, + const std::vector& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.size()); + copy_mem(&out[copy_offset], &in[0], in.size()); + return out; + } + +template +std::vector& operator+=(std::vector& out, T in) + { + out.push_back(in); + return out; + } + +template +std::vector& operator+=(std::vector& out, + const std::pair& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.second); + copy_mem(&out[copy_offset], in.first, in.second); + return out; + } + +template +std::vector& operator+=(std::vector& out, + const std::pair& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.second); + copy_mem(&out[copy_offset], in.first, in.second); + return out; + } + +/** +* Zeroise the values; length remains unchanged +* @param vec the vector to zeroise +*/ +template +void zeroise(std::vector& vec) + { + clear_mem(&vec[0], vec.size()); + } + +/** +* Zeroise the values then free the memory +* @param vec the vector to zeroise and free +*/ +template +void zap(std::vector& vec) + { + zeroise(vec); + vec.clear(); + vec.shrink_to_fit(); + } + +} + +#endif diff --git a/src/lib/asn1/alg_id.cpp b/src/lib/asn1/alg_id.cpp new file mode 100644 index 000000000..bb8dac80a --- /dev/null +++ b/src/lib/asn1/alg_id.cpp @@ -0,0 +1,105 @@ +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + const std::vector& param) + { + oid = alg_id; + parameters = param; + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + const std::vector& param) + { + oid = OIDS::lookup(alg_id); + parameters = param; + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + Encoding_Option option) + { + const byte DER_NULL[] = { 0x05, 0x00 }; + + oid = alg_id; + + if(option == USE_NULL_PARAM) + parameters += std::pair(DER_NULL, sizeof(DER_NULL)); + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + Encoding_Option option) + { + const byte DER_NULL[] = { 0x05, 0x00 }; + + oid = OIDS::lookup(alg_id); + + if(option == USE_NULL_PARAM) + parameters += std::pair(DER_NULL, sizeof(DER_NULL)); + } + +/* +* Compare two AlgorithmIdentifiers +*/ +bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + if(a1.oid != a2.oid) + return false; + if(a1.parameters != a2.parameters) + return false; + return true; + } + +/* +* Compare two AlgorithmIdentifiers +*/ +bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + return !(a1 == a2); + } + +/* +* DER encode an AlgorithmIdentifier +*/ +void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .raw_bytes(parameters) + .end_cons(); + } + +/* +* Decode a BER encoded AlgorithmIdentifier +*/ +void AlgorithmIdentifier::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .raw_bytes(parameters) + .end_cons(); + } + +} diff --git a/src/lib/asn1/alg_id.h b/src/lib/asn1/alg_id.h new file mode 100644 index 000000000..d8b40e700 --- /dev/null +++ b/src/lib/asn1/alg_id.h @@ -0,0 +1,49 @@ +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ALGORITHM_IDENTIFIER_H__ +#define BOTAN_ALGORITHM_IDENTIFIER_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Algorithm Identifier +*/ +class BOTAN_DLL AlgorithmIdentifier : public ASN1_Object + { + public: + enum Encoding_Option { USE_NULL_PARAM }; + + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + AlgorithmIdentifier() {} + AlgorithmIdentifier(const OID&, Encoding_Option); + AlgorithmIdentifier(const std::string&, Encoding_Option); + + AlgorithmIdentifier(const OID&, const std::vector&); + AlgorithmIdentifier(const std::string&, const std::vector&); + + OID oid; + std::vector parameters; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_DLL operator==(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); +bool BOTAN_DLL operator!=(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); + +} + +#endif diff --git a/src/lib/asn1/asn1_alt_name.cpp b/src/lib/asn1/asn1_alt_name.cpp new file mode 100644 index 000000000..2e7116bac --- /dev/null +++ b/src/lib/asn1/asn1_alt_name.cpp @@ -0,0 +1,241 @@ +/* +* AlternativeName +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Check if type is a known ASN.1 string type +*/ +bool is_string_type(ASN1_Tag tag) + { + return (tag == NUMERIC_STRING || + tag == PRINTABLE_STRING || + tag == VISIBLE_STRING || + tag == T61_STRING || + tag == IA5_STRING || + tag == UTF8_STRING || + tag == BMP_STRING); + } + +} + +/* +* Create an AlternativeName +*/ +AlternativeName::AlternativeName(const std::string& email_addr, + const std::string& uri, + const std::string& dns, + const std::string& ip) + { + add_attribute("RFC822", email_addr); + add_attribute("DNS", dns); + add_attribute("URI", uri); + add_attribute("IP", ip); + } + +/* +* Add an attribute to an alternative name +*/ +void AlternativeName::add_attribute(const std::string& type, + const std::string& str) + { + if(type == "" || str == "") + return; + + auto range = alt_info.equal_range(type); + for(auto j = range.first; j != range.second; ++j) + if(j->second == str) + return; + + multimap_insert(alt_info, type, str); + } + +/* +* Add an OtherName field +*/ +void AlternativeName::add_othername(const OID& oid, const std::string& value, + ASN1_Tag type) + { + if(value == "") + return; + multimap_insert(othernames, oid, ASN1_String(value, type)); + } + +/* +* Get the attributes of this alternative name +*/ +std::multimap AlternativeName::get_attributes() const + { + return alt_info; + } + +/* +* Get the otherNames +*/ +std::multimap AlternativeName::get_othernames() const + { + return othernames; + } + +/* +* Return all of the alternative names +*/ +std::multimap AlternativeName::contents() const + { + std::multimap names; + + for(auto i = alt_info.begin(); i != alt_info.end(); ++i) + multimap_insert(names, i->first, i->second); + + for(auto i = othernames.begin(); i != othernames.end(); ++i) + multimap_insert(names, OIDS::lookup(i->first), i->second.value()); + + return names; + } + +/* +* Return if this object has anything useful +*/ +bool AlternativeName::has_items() const + { + return (alt_info.size() > 0 || othernames.size() > 0); + } + +namespace { + +/* +* DER encode an AlternativeName entry +*/ +void encode_entries(DER_Encoder& encoder, + const std::multimap& attr, + const std::string& type, ASN1_Tag tagging) + { + auto range = attr.equal_range(type); + + for(auto i = range.first; i != range.second; ++i) + { + if(type == "RFC822" || type == "DNS" || type == "URI") + { + ASN1_String asn1_string(i->second, IA5_STRING); + encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.iso_8859()); + } + else if(type == "IP") + { + const u32bit ip = string_to_ipv4(i->second); + byte ip_buf[4] = { 0 }; + store_be(ip, ip_buf); + encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4); + } + } + } + +} + +/* +* DER encode an AlternativeName extension +*/ +void AlternativeName::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + encode_entries(der, alt_info, "RFC822", ASN1_Tag(1)); + encode_entries(der, alt_info, "DNS", ASN1_Tag(2)); + encode_entries(der, alt_info, "URI", ASN1_Tag(6)); + encode_entries(der, alt_info, "IP", ASN1_Tag(7)); + + for(auto i = othernames.begin(); i != othernames.end(); ++i) + { + der.start_explicit(0) + .encode(i->first) + .start_explicit(0) + .encode(i->second) + .end_explicit() + .end_explicit(); + } + + der.end_cons(); + } + +/* +* Decode a BER encoded AlternativeName +*/ +void AlternativeName::decode_from(BER_Decoder& source) + { + BER_Decoder names = source.start_cons(SEQUENCE); + + while(names.more_items()) + { + BER_Object obj = names.get_next_object(); + if((obj.class_tag != CONTEXT_SPECIFIC) && + (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))) + continue; + + const ASN1_Tag tag = obj.type_tag; + + if(tag == 0) + { + BER_Decoder othername(obj.value); + + OID oid; + othername.decode(oid); + if(othername.more_items()) + { + BER_Object othername_value_outer = othername.get_next_object(); + othername.verify_end(); + + if(othername_value_outer.type_tag != ASN1_Tag(0) || + othername_value_outer.class_tag != + (CONTEXT_SPECIFIC | CONSTRUCTED) + ) + throw Decoding_Error("Invalid tags on otherName value"); + + BER_Decoder othername_value_inner(othername_value_outer.value); + + BER_Object value = othername_value_inner.get_next_object(); + othername_value_inner.verify_end(); + + const ASN1_Tag value_type = value.type_tag; + + if(is_string_type(value_type) && value.class_tag == UNIVERSAL) + add_othername(oid, ASN1::to_string(value), value_type); + } + } + else if(tag == 1 || tag == 2 || tag == 6) + { + const std::string value = Charset::transcode(ASN1::to_string(obj), + LATIN1_CHARSET, + LOCAL_CHARSET); + + if(tag == 1) add_attribute("RFC822", value); + if(tag == 2) add_attribute("DNS", value); + if(tag == 6) add_attribute("URI", value); + } + else if(tag == 7) + { + if(obj.value.size() == 4) + { + const u32bit ip = load_be(&obj.value[0], 0); + add_attribute("IP", ipv4_to_string(ip)); + } + } + + } + } + +} diff --git a/src/lib/asn1/asn1_alt_name.h b/src/lib/asn1/asn1_alt_name.h new file mode 100644 index 000000000..f2c83ed2c --- /dev/null +++ b/src/lib/asn1/asn1_alt_name.h @@ -0,0 +1,47 @@ +/* +* Common ASN.1 Objects +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASN1_ALT_NAME_H__ +#define BOTAN_ASN1_ALT_NAME_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Alternative Name +*/ +class BOTAN_DLL AlternativeName : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::multimap contents() const; + + void add_attribute(const std::string&, const std::string&); + std::multimap get_attributes() const; + + void add_othername(const OID&, const std::string&, ASN1_Tag); + std::multimap get_othernames() const; + + bool has_items() const; + + AlternativeName(const std::string& = "", const std::string& = "", + const std::string& = "", const std::string& = ""); + private: + std::multimap alt_info; + std::multimap othernames; + }; + +} + +#endif diff --git a/src/lib/asn1/asn1_attribute.cpp b/src/lib/asn1/asn1_attribute.cpp new file mode 100644 index 000000000..dff52bef9 --- /dev/null +++ b/src/lib/asn1/asn1_attribute.cpp @@ -0,0 +1,60 @@ +/* +* Attribute +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an Attribute +*/ +Attribute::Attribute(const OID& attr_oid, const std::vector& attr_value) + { + oid = attr_oid; + parameters = attr_value; + } + +/* +* Create an Attribute +*/ +Attribute::Attribute(const std::string& attr_oid, + const std::vector& attr_value) + { + oid = OIDS::lookup(attr_oid); + parameters = attr_value; + } + +/* +* DER encode a Attribute +*/ +void Attribute::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded Attribute +*/ +void Attribute::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +} diff --git a/src/lib/asn1/asn1_attribute.h b/src/lib/asn1/asn1_attribute.h new file mode 100644 index 000000000..877135803 --- /dev/null +++ b/src/lib/asn1/asn1_attribute.h @@ -0,0 +1,36 @@ +/* +* ASN.1 Attribute +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASN1_ATTRIBUTE_H__ +#define BOTAN_ASN1_ATTRIBUTE_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Attribute +*/ +class BOTAN_DLL Attribute : public ASN1_Object + { + public: + void encode_into(class DER_Encoder& to) const; + void decode_from(class BER_Decoder& from); + + OID oid; + std::vector parameters; + + Attribute() {} + Attribute(const OID&, const std::vector&); + Attribute(const std::string&, const std::vector&); + }; + +} + +#endif diff --git a/src/lib/asn1/asn1_obj.cpp b/src/lib/asn1/asn1_obj.cpp new file mode 100644 index 000000000..898e91614 --- /dev/null +++ b/src/lib/asn1/asn1_obj.cpp @@ -0,0 +1,68 @@ +/* +* ASN.1 Internals +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* BER Decoding Exceptions +*/ +BER_Decoding_Error::BER_Decoding_Error(const std::string& str) : + Decoding_Error("BER: " + str) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) : + BER_Decoding_Error(str + ": " + std::to_string(tag)) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, + ASN1_Tag tag1, ASN1_Tag tag2) : + BER_Decoding_Error(str + ": " + std::to_string(tag1) + "/" + std::to_string(tag2)) {} + +namespace ASN1 { + +/* +* Put some arbitrary bytes into a SEQUENCE +*/ +std::vector put_in_sequence(const std::vector& contents) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .raw_bytes(contents) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Convert a BER object into a string object +*/ +std::string to_string(const BER_Object& obj) + { + return std::string(reinterpret_cast(&obj.value[0]), + obj.value.size()); + } + +/* +* Do heuristic tests for BER data +*/ +bool maybe_BER(DataSource& source) + { + byte first_byte; + if(!source.peek_byte(first_byte)) + throw Stream_IO_Error("ASN1::maybe_BER: Source was empty"); + + if(first_byte == (SEQUENCE | CONSTRUCTED)) + return true; + return false; + } + +} + +} diff --git a/src/lib/asn1/asn1_obj.h b/src/lib/asn1/asn1_obj.h new file mode 100644 index 000000000..564f4ecdb --- /dev/null +++ b/src/lib/asn1/asn1_obj.h @@ -0,0 +1,124 @@ +/* +* ASN.1 Internals +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASN1_H__ +#define BOTAN_ASN1_H__ + +#include +#include + +namespace Botan { + +/** +* ASN.1 Type and Class Tags +*/ +enum ASN1_Tag { + UNIVERSAL = 0x00, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + + CONSTRUCTED = 0x20, + + PRIVATE = CONSTRUCTED | CONTEXT_SPECIFIC, + + EOC = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL_TAG = 0x05, + OBJECT_ID = 0x06, + ENUMERATED = 0x0A, + SEQUENCE = 0x10, + SET = 0x11, + + UTF8_STRING = 0x0C, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + IA5_STRING = 0x16, + VISIBLE_STRING = 0x1A, + BMP_STRING = 0x1E, + + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + + NO_OBJECT = 0xFF00, + DIRECTORY_STRING = 0xFF01 +}; + +/** +* Basic ASN.1 Object Interface +*/ +class BOTAN_DLL ASN1_Object + { + public: + /** + * Encode whatever this object is into to + * @param to the DER_Encoder that will be written to + */ + virtual void encode_into(class DER_Encoder& to) const = 0; + + /** + * Decode whatever this object is from from + * @param from the BER_Decoder that will be read from + */ + virtual void decode_from(class BER_Decoder& from) = 0; + + virtual ~ASN1_Object() {} + }; + +/** +* BER Encoded Object +*/ +class BOTAN_DLL BER_Object + { + public: + void assert_is_a(ASN1_Tag, ASN1_Tag); + + ASN1_Tag type_tag, class_tag; + secure_vector value; + }; + +/* +* ASN.1 Utility Functions +*/ +class DataSource; + +namespace ASN1 { + +std::vector put_in_sequence(const std::vector& val); +std::string to_string(const BER_Object& obj); + +/** +* Heuristics tests; is this object possibly BER? +* @param src a data source that will be peeked at but not modified +*/ +bool maybe_BER(DataSource& src); + +} + +/** +* General BER Decoding Error Exception +*/ +struct BOTAN_DLL BER_Decoding_Error : public Decoding_Error + { + BER_Decoding_Error(const std::string&); + }; + +/** +* Exception For Incorrect BER Taggings +*/ +struct BOTAN_DLL BER_Bad_Tag : public BER_Decoding_Error + { + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag); + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag1, ASN1_Tag tag2); + }; + +} + +#endif diff --git a/src/lib/asn1/asn1_oid.cpp b/src/lib/asn1/asn1_oid.cpp new file mode 100644 index 000000000..964315080 --- /dev/null +++ b/src/lib/asn1/asn1_oid.cpp @@ -0,0 +1,189 @@ +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* ASN.1 OID Constructor +*/ +OID::OID(const std::string& oid_str) + { + if(oid_str != "") + { + try + { + id = parse_asn1_oid(oid_str); + } + catch(...) + { + throw Invalid_OID(oid_str); + } + + if(id.size() < 2 || id[0] > 2) + throw Invalid_OID(oid_str); + if((id[0] == 0 || id[0] == 1) && id[1] > 39) + throw Invalid_OID(oid_str); + } + } + +/* +* Clear the current OID +*/ +void OID::clear() + { + id.clear(); + } + +/* +* Return this OID as a string +*/ +std::string OID::as_string() const + { + std::string oid_str; + for(size_t i = 0; i != id.size(); ++i) + { + oid_str += std::to_string(id[i]); + if(i != id.size() - 1) + oid_str += '.'; + } + return oid_str; + } + +/* +* OID equality comparison +*/ +bool OID::operator==(const OID& oid) const + { + if(id.size() != oid.id.size()) + return false; + for(size_t i = 0; i != id.size(); ++i) + if(id[i] != oid.id[i]) + return false; + return true; + } + +/* +* Append another component to the OID +*/ +OID& OID::operator+=(u32bit component) + { + id.push_back(component); + return (*this); + } + +/* +* Append another component to the OID +*/ +OID operator+(const OID& oid, u32bit component) + { + OID new_oid(oid); + new_oid += component; + return new_oid; + } + +/* +* OID inequality comparison +*/ +bool operator!=(const OID& a, const OID& b) + { + return !(a == b); + } + +/* +* Compare two OIDs +*/ +bool operator<(const OID& a, const OID& b) + { + const std::vector& oid1 = a.get_id(); + const std::vector& oid2 = b.get_id(); + + if(oid1.size() < oid2.size()) + return true; + if(oid1.size() > oid2.size()) + return false; + for(size_t i = 0; i != oid1.size(); ++i) + { + if(oid1[i] < oid2[i]) + return true; + if(oid1[i] > oid2[i]) + return false; + } + return false; + } + +/* +* DER encode an OBJECT IDENTIFIER +*/ +void OID::encode_into(DER_Encoder& der) const + { + if(id.size() < 2) + throw Invalid_Argument("OID::encode_into: OID is invalid"); + + std::vector encoding; + encoding.push_back(40 * id[0] + id[1]); + + for(size_t i = 2; i != id.size(); ++i) + { + if(id[i] == 0) + encoding.push_back(0); + else + { + size_t blocks = high_bit(id[i]) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + for(size_t j = 0; j != blocks - 1; ++j) + encoding.push_back(0x80 | ((id[i] >> 7*(blocks-j-1)) & 0x7F)); + encoding.push_back(id[i] & 0x7F); + } + } + der.add_object(OBJECT_ID, UNIVERSAL, encoding); + } + +/* +* Decode a BER encoded OBJECT IDENTIFIER +*/ +void OID::decode_from(BER_Decoder& decoder) + { + BER_Object obj = decoder.get_next_object(); + if(obj.type_tag != OBJECT_ID || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Error decoding OID, unknown tag", + obj.type_tag, obj.class_tag); + if(obj.value.size() < 2) + throw BER_Decoding_Error("OID encoding is too short"); + + + clear(); + id.push_back(obj.value[0] / 40); + id.push_back(obj.value[0] % 40); + + size_t i = 0; + while(i != obj.value.size() - 1) + { + u32bit component = 0; + while(i != obj.value.size() - 1) + { + ++i; + + if(component >> (32-7)) + throw Decoding_Error("OID component overflow"); + + component = (component << 7) + (obj.value[i] & 0x7F); + + if(!(obj.value[i] & 0x80)) + break; + } + id.push_back(component); + } + } + +} diff --git a/src/lib/asn1/asn1_oid.h b/src/lib/asn1/asn1_oid.h new file mode 100644 index 000000000..a0b1edeba --- /dev/null +++ b/src/lib/asn1/asn1_oid.h @@ -0,0 +1,96 @@ +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASN1_OID_H__ +#define BOTAN_ASN1_OID_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents ASN.1 object identifiers. +*/ +class BOTAN_DLL OID : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + /** + * Find out whether this OID is empty + * @return true is no OID value is set + */ + bool empty() const { return id.size() == 0; } + + /** + * Get this OID as list (vector) of its components. + * @return vector representing this OID + */ + const std::vector& get_id() const { return id; } + + /** + * Get this OID as a string + * @return string representing this OID + */ + std::string as_string() const; + + /** + * Compare two OIDs. + * @return true if they are equal, false otherwise + */ + bool operator==(const OID&) const; + + /** + * Reset this instance to an empty OID. + */ + void clear(); + + /** + * Add a component to this OID. + * @param new_comp the new component to add to the end of this OID + * @return reference to *this + */ + OID& operator+=(u32bit new_comp); + + /** + * Construct an OID from a string. + * @param str a string in the form "a.b.c" etc., where a,b,c are numbers + */ + OID(const std::string& str = ""); + private: + std::vector id; + }; + +/** +* Append another component onto the OID. +* @param oid the OID to add the new component to +* @param new_comp the new component to add +*/ +OID BOTAN_DLL operator+(const OID& oid, u32bit new_comp); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is not equal to b +*/ +bool BOTAN_DLL operator!=(const OID& a, const OID& b); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is lexicographically smaller than b +*/ +bool BOTAN_DLL operator<(const OID& a, const OID& b); + +} + +#endif diff --git a/src/lib/asn1/asn1_str.cpp b/src/lib/asn1/asn1_str.cpp new file mode 100644 index 000000000..44db189f9 --- /dev/null +++ b/src/lib/asn1/asn1_str.cpp @@ -0,0 +1,148 @@ +/* +* Simple ASN.1 String Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Choose an encoding for the string +*/ +ASN1_Tag choose_encoding(const std::string& str, + const std::string& type) + { + static const byte IS_PRINTABLE[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + for(size_t i = 0; i != str.size(); ++i) + { + if(!IS_PRINTABLE[static_cast(str[i])]) + { + if(type == "utf8") return UTF8_STRING; + if(type == "latin1") return T61_STRING; + throw Invalid_Argument("choose_encoding: Bad string type " + type); + } + } + return PRINTABLE_STRING; + } + +} + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : tag(t) + { + iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); + + if(tag == DIRECTORY_STRING) + tag = choose_encoding(iso_8859_str, "latin1"); + + if(tag != NUMERIC_STRING && + tag != PRINTABLE_STRING && + tag != VISIBLE_STRING && + tag != T61_STRING && + tag != IA5_STRING && + tag != UTF8_STRING && + tag != BMP_STRING) + throw Invalid_Argument("ASN1_String: Unknown string type " + + std::to_string(tag)); + } + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str) + { + iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); + tag = choose_encoding(iso_8859_str, "latin1"); + } + +/* +* Return this string in ISO 8859-1 encoding +*/ +std::string ASN1_String::iso_8859() const + { + return iso_8859_str; + } + +/* +* Return this string in local encoding +*/ +std::string ASN1_String::value() const + { + return Charset::transcode(iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET); + } + +/* +* Return the type of this string object +*/ +ASN1_Tag ASN1_String::tagging() const + { + return tag; + } + +/* +* DER encode an ASN1_String +*/ +void ASN1_String::encode_into(DER_Encoder& encoder) const + { + std::string value = iso_8859(); + if(tagging() == UTF8_STRING) + value = Charset::transcode(value, LATIN1_CHARSET, UTF8_CHARSET); + encoder.add_object(tagging(), UNIVERSAL, value); + } + +/* +* Decode a BER encoded ASN1_String +*/ +void ASN1_String::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + + Character_Set charset_is; + + if(obj.type_tag == BMP_STRING) + charset_is = UCS2_CHARSET; + else if(obj.type_tag == UTF8_STRING) + charset_is = UTF8_CHARSET; + else + charset_is = LATIN1_CHARSET; + + *this = ASN1_String( + Charset::transcode(ASN1::to_string(obj), charset_is, LOCAL_CHARSET), + obj.type_tag); + } + +} diff --git a/src/lib/asn1/asn1_str.h b/src/lib/asn1/asn1_str.h new file mode 100644 index 000000000..42f1ef5ae --- /dev/null +++ b/src/lib/asn1/asn1_str.h @@ -0,0 +1,38 @@ +/* +* ASN.1 string type +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASN1_STRING_H__ +#define BOTAN_ASN1_STRING_H__ + +#include + +namespace Botan { + +/** +* Simple String +*/ +class BOTAN_DLL ASN1_String : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::string value() const; + std::string iso_8859() const; + + ASN1_Tag tagging() const; + + ASN1_String(const std::string& = ""); + ASN1_String(const std::string&, ASN1_Tag); + private: + std::string iso_8859_str; + ASN1_Tag tag; + }; + +} + +#endif diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp new file mode 100644 index 000000000..32f214e53 --- /dev/null +++ b/src/lib/asn1/asn1_time.cpp @@ -0,0 +1,303 @@ +/* +* X.509 Time Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an X509_Time +*/ +X509_Time::X509_Time(const std::string& time_str) + { + set_to(time_str); + } + +/* +* Create a X509_Time from a time point +*/ +X509_Time::X509_Time(const std::chrono::system_clock::time_point& time) + { + calendar_point cal = calendar_value(time); + + year = cal.year; + month = cal.month; + day = cal.day; + hour = cal.hour; + minute = cal.minutes; + second = cal.seconds; + + tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME; + } + +/* +* Create an X509_Time +*/ +X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t) + { + set_to(t_spec, tag); + } + +/* +* Set the time with a human readable string +*/ +void X509_Time::set_to(const std::string& time_str) + { + if(time_str == "") + { + year = month = day = hour = minute = second = 0; + tag = NO_OBJECT; + return; + } + + std::vector params; + std::string current; + + for(size_t j = 0; j != time_str.size(); ++j) + { + if(Charset::is_digit(time_str[j])) + current += time_str[j]; + else + { + if(current != "") + params.push_back(current); + current.clear(); + } + } + if(current != "") + params.push_back(current); + + if(params.size() < 3 || params.size() > 6) + throw Invalid_Argument("Invalid time specification " + time_str); + + year = to_u32bit(params[0]); + month = to_u32bit(params[1]); + day = to_u32bit(params[2]); + hour = (params.size() >= 4) ? to_u32bit(params[3]) : 0; + minute = (params.size() >= 5) ? to_u32bit(params[4]) : 0; + second = (params.size() == 6) ? to_u32bit(params[5]) : 0; + + tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME; + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + time_str); + } + +/* +* Set the time with an ISO time format string +*/ +void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) + { + if(spec_tag == GENERALIZED_TIME) + { + if(t_spec.size() != 13 && t_spec.size() != 15) + throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec); + } + else if(spec_tag == UTC_TIME) + { + if(t_spec.size() != 11 && t_spec.size() != 13) + throw Invalid_Argument("Invalid UTCTime: " + t_spec); + } + else + { + throw Invalid_Argument("Invalid time tag " + std::to_string(spec_tag) + " val " + t_spec); + } + + if(t_spec[t_spec.size()-1] != 'Z') + throw Invalid_Argument("Invalid time encoding: " + t_spec); + + const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4; + + std::vector params; + std::string current; + + for(size_t j = 0; j != YEAR_SIZE; ++j) + current += t_spec[j]; + params.push_back(current); + current.clear(); + + for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j) + { + current += t_spec[j]; + if(current.size() == 2) + { + params.push_back(current); + current.clear(); + } + } + + year = to_u32bit(params[0]); + month = to_u32bit(params[1]); + day = to_u32bit(params[2]); + hour = to_u32bit(params[3]); + minute = to_u32bit(params[4]); + second = (params.size() == 6) ? to_u32bit(params[5]) : 0; + tag = spec_tag; + + if(spec_tag == UTC_TIME) + { + if(year >= 50) year += 1900; + else year += 2000; + } + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + t_spec); + } + +/* +* DER encode a X509_Time +*/ +void X509_Time::encode_into(DER_Encoder& der) const + { + if(tag != GENERALIZED_TIME && tag != UTC_TIME) + throw Invalid_Argument("X509_Time: Bad encoding tag"); + + der.add_object(tag, UNIVERSAL, + Charset::transcode(as_string(), + LOCAL_CHARSET, + LATIN1_CHARSET)); + } + +/* +* Decode a BER encoded X509_Time +*/ +void X509_Time::decode_from(BER_Decoder& source) + { + BER_Object ber_time = source.get_next_object(); + + set_to(Charset::transcode(ASN1::to_string(ber_time), + LATIN1_CHARSET, + LOCAL_CHARSET), + ber_time.type_tag); + } + +/* +* Return a string representation of the time +*/ +std::string X509_Time::as_string() const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::as_string: No time set"); + + u32bit full_year = year; + + if(tag == UTC_TIME) + { + if(year < 1950 || year >= 2050) + throw Encoding_Error("X509_Time: The time " + readable_string() + + " cannot be encoded as a UTCTime"); + + full_year = (year >= 2000) ? (year - 2000) : (year - 1900); + } + + std::string repr = std::to_string(full_year*10000000000 + + month*100000000 + + day*1000000 + + hour*10000 + + minute*100 + + second) + "Z"; + + u32bit desired_size = (tag == UTC_TIME) ? 13 : 15; + + while(repr.size() < desired_size) + repr = "0" + repr; + + return repr; + } + +/* +* Return if the time has been set somehow +*/ +bool X509_Time::time_is_set() const + { + return (year != 0); + } + +/* +* Return a human readable string representation +*/ +std::string X509_Time::readable_string() const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::readable_string: No time set"); + + std::string output(24, 0); + + std::sprintf(&output[0], "%04d/%02d/%02d %02d:%02d:%02d UTC", + year, month, day, hour, minute, second); + + output.resize(23); // remove trailing null + + return output; + } + +/* +* Do a general sanity check on the time +*/ +bool X509_Time::passes_sanity_check() const + { + if(year < 1950 || year > 2100) + return false; + if(month == 0 || month > 12) + return false; + if(day == 0 || day > 31) + return false; + if(hour >= 24 || minute > 60 || second > 60) + return false; + return true; + } + +/* +* Compare this time against another +*/ +s32bit X509_Time::cmp(const X509_Time& other) const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::cmp: No time set"); + + const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0; + + if(year < other.year) return EARLIER; + if(year > other.year) return LATER; + if(month < other.month) return EARLIER; + if(month > other.month) return LATER; + if(day < other.day) return EARLIER; + if(day > other.day) return LATER; + if(hour < other.hour) return EARLIER; + if(hour > other.hour) return LATER; + if(minute < other.minute) return EARLIER; + if(minute > other.minute) return LATER; + if(second < other.second) return EARLIER; + if(second > other.second) return LATER; + + return SAME_TIME; + } + +/* +* Compare two X509_Times for in various ways +*/ +bool operator==(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) == 0); } +bool operator!=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) != 0); } + +bool operator<=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) <= 0); } +bool operator>=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) >= 0); } + +bool operator<(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) < 0); } +bool operator>(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) > 0); } + +} diff --git a/src/lib/asn1/asn1_time.h b/src/lib/asn1/asn1_time.h new file mode 100644 index 000000000..95baacd86 --- /dev/null +++ b/src/lib/asn1/asn1_time.h @@ -0,0 +1,57 @@ +/* +* ASN.1 Time Representation +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASN1_TIME_H__ +#define BOTAN_ASN1_TIME_H__ + +#include +#include + +namespace Botan { + +/** +* X.509 Time +*/ +class BOTAN_DLL X509_Time : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::string as_string() const; + std::string readable_string() const; + bool time_is_set() const; + + std::string to_string() const { return readable_string(); } + + s32bit cmp(const X509_Time&) const; + + void set_to(const std::string&); + void set_to(const std::string&, ASN1_Tag); + + X509_Time(const std::chrono::system_clock::time_point& time); + X509_Time(const std::string& = ""); + X509_Time(const std::string&, ASN1_Tag); + private: + bool passes_sanity_check() const; + u32bit year, month, day, hour, minute, second; + ASN1_Tag tag; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_DLL operator==(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator!=(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator<=(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator>=(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator<(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator>(const X509_Time&, const X509_Time&); + +} + +#endif diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp new file mode 100644 index 000000000..81b2e34f6 --- /dev/null +++ b/src/lib/asn1/ber_dec.cpp @@ -0,0 +1,561 @@ +/* +* BER Decoder +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* BER decode an ASN.1 type tag +*/ +size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag) + { + byte b; + if(!ber->read_byte(b)) + { + class_tag = type_tag = NO_OBJECT; + return 0; + } + + if((b & 0x1F) != 0x1F) + { + type_tag = ASN1_Tag(b & 0x1F); + class_tag = ASN1_Tag(b & 0xE0); + return 1; + } + + size_t tag_bytes = 1; + class_tag = ASN1_Tag(b & 0xE0); + + size_t tag_buf = 0; + while(true) + { + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Long-form tag truncated"); + if(tag_buf & 0xFF000000) + throw BER_Decoding_Error("Long-form tag overflowed 32 bits"); + ++tag_bytes; + tag_buf = (tag_buf << 7) | (b & 0x7F); + if((b & 0x80) == 0) break; + } + type_tag = ASN1_Tag(tag_buf); + return tag_bytes; + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource*); + +/* +* BER decode an ASN.1 length field +*/ +size_t decode_length(DataSource* ber, size_t& field_size) + { + byte b; + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Length field not found"); + field_size = 1; + if((b & 0x80) == 0) + return b; + + field_size += (b & 0x7F); + if(field_size == 1) return find_eoc(ber); + if(field_size > 5) + throw BER_Decoding_Error("Length field is too large"); + + size_t length = 0; + + for(size_t i = 0; i != field_size - 1; ++i) + { + if(get_byte(0, length) != 0) + throw BER_Decoding_Error("Field length overflow"); + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Corrupted length field"); + length = (length << 8) | b; + } + return length; + } + +/* +* BER decode an ASN.1 length field +*/ +size_t decode_length(DataSource* ber) + { + size_t dummy; + return decode_length(ber, dummy); + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource* ber) + { + secure_vector buffer(DEFAULT_BUFFERSIZE), data; + + while(true) + { + const size_t got = ber->peek(&buffer[0], buffer.size(), data.size()); + if(got == 0) + break; + + data += std::make_pair(&buffer[0], got); + } + + DataSource_Memory source(data); + data.clear(); + + size_t length = 0; + while(true) + { + ASN1_Tag type_tag, class_tag; + size_t tag_size = decode_tag(&source, type_tag, class_tag); + if(type_tag == NO_OBJECT) + break; + + size_t length_size = 0; + size_t item_size = decode_length(&source, length_size); + source.discard_next(item_size); + + length += item_size + length_size + tag_size; + + if(type_tag == EOC) + break; + } + return length; + } + +} + +/* +* Check a type invariant on BER data +*/ +void BER_Object::assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(this->type_tag != type_tag || this->class_tag != class_tag) + throw BER_Decoding_Error("Tag mismatch when decoding got " + + std::to_string(this->type_tag) + "/" + + std::to_string(this->class_tag) + " expected " + + std::to_string(type_tag) + "/" + + std::to_string(class_tag)); + } + +/* +* Check if more objects are there +*/ +bool BER_Decoder::more_items() const + { + if(source->end_of_data() && (pushed.type_tag == NO_OBJECT)) + return false; + return true; + } + +/* +* Verify that no bytes remain in the source +*/ +BER_Decoder& BER_Decoder::verify_end() + { + if(!source->end_of_data() || (pushed.type_tag != NO_OBJECT)) + throw Invalid_State("BER_Decoder::verify_end called, but data remains"); + return (*this); + } + +/* +* Save all the bytes remaining in the source +*/ +BER_Decoder& BER_Decoder::raw_bytes(secure_vector& out) + { + out.clear(); + byte buf; + while(source->read_byte(buf)) + out.push_back(buf); + return (*this); + } + +BER_Decoder& BER_Decoder::raw_bytes(std::vector& out) + { + out.clear(); + byte buf; + while(source->read_byte(buf)) + out.push_back(buf); + return (*this); + } + +/* +* Discard all the bytes remaining in the source +*/ +BER_Decoder& BER_Decoder::discard_remaining() + { + byte buf; + while(source->read_byte(buf)) + ; + return (*this); + } + +/* +* Return the BER encoding of the next object +*/ +BER_Object BER_Decoder::get_next_object() + { + BER_Object next; + + if(pushed.type_tag != NO_OBJECT) + { + next = pushed; + pushed.class_tag = pushed.type_tag = NO_OBJECT; + return next; + } + + decode_tag(source, next.type_tag, next.class_tag); + if(next.type_tag == NO_OBJECT) + return next; + + size_t length = decode_length(source); + next.value.resize(length); + if(source->read(&next.value[0], length) != length) + throw BER_Decoding_Error("Value truncated"); + + if(next.type_tag == EOC && next.class_tag == UNIVERSAL) + return get_next_object(); + + return next; + } + +BER_Decoder& BER_Decoder::get_next(BER_Object& ber) + { + ber = get_next_object(); + return (*this); + } + +/* +* Push a object back into the stream +*/ +void BER_Decoder::push_back(const BER_Object& obj) + { + if(pushed.type_tag != NO_OBJECT) + throw Invalid_State("BER_Decoder: Only one push back is allowed"); + pushed = obj; + } + +/* +* Begin decoding a CONSTRUCTED type +*/ +BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + + BER_Decoder result(&obj.value[0], obj.value.size()); + result.parent = this; + return result; + } + +/* +* Finish decoding a CONSTRUCTED type +*/ +BER_Decoder& BER_Decoder::end_cons() + { + if(!parent) + throw Invalid_State("BER_Decoder::end_cons called with NULL parent"); + if(!source->end_of_data()) + throw Decoding_Error("BER_Decoder::end_cons called with data left"); + return (*parent); + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(DataSource& src) + { + source = &src; + owns = false; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = nullptr; + } + +/* +* BER_Decoder Constructor + */ +BER_Decoder::BER_Decoder(const byte data[], size_t length) + { + source = new DataSource_Memory(data, length); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = nullptr; + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const secure_vector& data) + { + source = new DataSource_Memory(data); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = nullptr; + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const std::vector& data) + { + source = new DataSource_Memory(&data[0], data.size()); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = nullptr; + } + +/* +* BER_Decoder Copy Constructor +*/ +BER_Decoder::BER_Decoder(const BER_Decoder& other) + { + source = other.source; + owns = false; + if(other.owns) + { + other.owns = false; + owns = true; + } + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = other.parent; + } + +/* +* BER_Decoder Destructor +*/ +BER_Decoder::~BER_Decoder() + { + if(owns) + delete source; + source = nullptr; + } + +/* +* Request for an object to decode itself +*/ +BER_Decoder& BER_Decoder::decode(ASN1_Object& obj, + ASN1_Tag, ASN1_Tag) + { + obj.decode_from(*this); + return (*this); + } + +/* +* Decode a BER encoded NULL +*/ +BER_Decoder& BER_Decoder::decode_null() + { + BER_Object obj = get_next_object(); + obj.assert_is_a(NULL_TAG, UNIVERSAL); + if(obj.value.size()) + throw BER_Decoding_Error("NULL object had nonzero size"); + return (*this); + } + +/* +* Decode a BER encoded BOOLEAN +*/ +BER_Decoder& BER_Decoder::decode(bool& out) + { + return decode(out, BOOLEAN, UNIVERSAL); + } + +/* +* Decode a small BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(size_t& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + +/* +* Decode a BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(BigInt& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + +BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) + { + secure_vector out_vec; + decode(out_vec, OCTET_STRING); + out = BigInt::decode(&out_vec[0], out_vec.size()); + return (*this); + } + +std::vector BER_Decoder::get_next_octet_string() + { + std::vector out_vec; + decode(out_vec, OCTET_STRING); + return out_vec; + } + +/* +* Decode a BER encoded BOOLEAN +*/ +BER_Decoder& BER_Decoder::decode(bool& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.value.size() != 1) + throw BER_Decoding_Error("BER boolean value had invalid size"); + + out = (obj.value[0]) ? true : false; + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(size_t& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.bits() > 32) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + out = 0; + for(size_t i = 0; i != 4; ++i) + out = (out << 8) | integer.byte_at(3-i); + + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +u64bit BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t T_bytes) + { + if(T_bytes > 8) + throw BER_Decoding_Error("Can't decode small integer over 8 bytes"); + + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.bits() > 8*T_bytes) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + u64bit out = 0; + for(size_t i = 0; i != 8; ++i) + out = (out << 8) | integer.byte_at(7-i); + + return out; + } + +/* +* Decode a BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(BigInt& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.value.empty()) + out = 0; + else + { + const bool negative = (obj.value[0] & 0x80) ? true : false; + + if(negative) + { + for(size_t i = obj.value.size(); i > 0; --i) + if(obj.value[i-1]--) + break; + for(size_t i = 0; i != obj.value.size(); ++i) + obj.value[i] = ~obj.value[i]; + } + + out = BigInt(&obj.value[0], obj.value.size()); + + if(negative) + out.flip_sign(); + } + + return (*this); + } + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(secure_vector& out, ASN1_Tag real_type) + { + return decode(out, real_type, real_type, UNIVERSAL); + } + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(std::vector& out, ASN1_Tag real_type) + { + return decode(out, real_type, real_type, UNIVERSAL); + } + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(secure_vector& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(real_type == OCTET_STRING) + buffer = obj.value; + else + { + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); + + buffer.resize(obj.value.size() - 1); + copy_mem(&buffer[0], &obj.value[1], obj.value.size() - 1); + } + return (*this); + } + +BER_Decoder& BER_Decoder::decode(std::vector& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(real_type == OCTET_STRING) + buffer = unlock(obj.value); + else + { + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); + + buffer.resize(obj.value.size() - 1); + copy_mem(&buffer[0], &obj.value[1], obj.value.size() - 1); + } + return (*this); + } + +} diff --git a/src/lib/asn1/ber_dec.h b/src/lib/asn1/ber_dec.h new file mode 100644 index 000000000..ebfa91c85 --- /dev/null +++ b/src/lib/asn1/ber_dec.h @@ -0,0 +1,260 @@ +/* +* BER Decoder +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BER_DECODER_H__ +#define BOTAN_BER_DECODER_H__ + +#include +#include + +namespace Botan { + +/** +* BER Decoding Object +*/ +class BOTAN_DLL BER_Decoder + { + public: + BER_Object get_next_object(); + + std::vector get_next_octet_string(); + + void push_back(const BER_Object& obj); + + bool more_items() const; + BER_Decoder& verify_end(); + BER_Decoder& discard_remaining(); + + BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL); + BER_Decoder& end_cons(); + + BER_Decoder& get_next(BER_Object& ber); + + BER_Decoder& raw_bytes(secure_vector& v); + BER_Decoder& raw_bytes(std::vector& v); + + BER_Decoder& decode_null(); + BER_Decoder& decode(bool& v); + BER_Decoder& decode(size_t& v); + BER_Decoder& decode(class BigInt& v); + BER_Decoder& decode(std::vector& v, ASN1_Tag type_tag); + BER_Decoder& decode(secure_vector& v, ASN1_Tag type_tag); + + BER_Decoder& decode(bool& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(size_t& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(class BigInt& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(std::vector& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(secure_vector& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(class ASN1_Object& obj, + ASN1_Tag type_tag = NO_OBJECT, + ASN1_Tag class_tag = NO_OBJECT); + + BER_Decoder& decode_octet_string_bigint(class BigInt& b); + + u64bit decode_constrained_integer(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t T_bytes); + + template BER_Decoder& decode_integer_type(T& out) + { + return decode_integer_type(out, INTEGER, UNIVERSAL); + } + + template + BER_Decoder& decode_integer_type(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + out = decode_constrained_integer(type_tag, class_tag, sizeof(out)); + return (*this); + } + + template + BER_Decoder& decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value = T()); + + template + BER_Decoder& decode_optional_implicit( + T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + ASN1_Tag real_type, + ASN1_Tag real_class, + const T& default_value = T()); + + template + BER_Decoder& decode_list(std::vector& out, + ASN1_Tag type_tag = SEQUENCE, + ASN1_Tag class_tag = UNIVERSAL); + + template + BER_Decoder& decode_and_check(const T& expected, + const std::string& error_msg) + { + T actual; + decode(actual); + + if(actual != expected) + throw Decoding_Error(error_msg); + + return (*this); + } + + /* + * Decode an OPTIONAL string type + */ + template + BER_Decoder& decode_optional_string(std::vector& out, + ASN1_Tag real_type, + u16bit type_no, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + BER_Object obj = get_next_object(); + + ASN1_Tag type_tag = static_cast(type_no); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) + BER_Decoder(obj.value).decode(out, real_type).verify_end(); + else + { + push_back(obj); + decode(out, real_type, type_tag, class_tag); + } + } + else + { + out.clear(); + push_back(obj); + } + + return (*this); + } + + BER_Decoder& operator=(const BER_Decoder&) = delete; + + BER_Decoder(DataSource&); + + BER_Decoder(const byte[], size_t); + + BER_Decoder(const secure_vector&); + + BER_Decoder(const std::vector& vec); + + BER_Decoder(const BER_Decoder&); + ~BER_Decoder(); + private: + BER_Decoder* parent; + DataSource* source; + BER_Object pushed; + mutable bool owns; + }; + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template +BER_Decoder& BER_Decoder::decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) + BER_Decoder(obj.value).decode(out).verify_end(); + else + { + push_back(obj); + decode(out, type_tag, class_tag); + } + } + else + { + out = default_value; + push_back(obj); + } + + return (*this); + } + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template +BER_Decoder& BER_Decoder::decode_optional_implicit( + T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + ASN1_Tag real_type, + ASN1_Tag real_class, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + obj.type_tag = real_type; + obj.class_tag = real_class; + push_back(obj); + decode(out, real_type, real_class); + } + else + { + out = default_value; + push_back(obj); + } + + return (*this); + } +/* +* Decode a list of homogenously typed values +*/ +template +BER_Decoder& BER_Decoder::decode_list(std::vector& vec, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Decoder list = start_cons(type_tag, class_tag); + + while(list.more_items()) + { + T value; + list.decode(value); + vec.push_back(value); + } + + list.end_cons(); + + return (*this); + } + +} + +#endif diff --git a/src/lib/asn1/der_enc.cpp b/src/lib/asn1/der_enc.cpp new file mode 100644 index 000000000..c1e5fd45c --- /dev/null +++ b/src/lib/asn1/der_enc.cpp @@ -0,0 +1,410 @@ +/* +* DER Encoder +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* DER encode an ASN.1 type tag +*/ +secure_vector encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if((class_tag | 0xE0) != 0xE0) + throw Encoding_Error("DER_Encoder: Invalid class tag " + + std::to_string(class_tag)); + + secure_vector encoded_tag; + if(type_tag <= 30) + encoded_tag.push_back(static_cast(type_tag | class_tag)); + else + { + size_t blocks = high_bit(type_tag) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + encoded_tag.push_back(class_tag | 0x1F); + for(size_t i = 0; i != blocks - 1; ++i) + encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F)); + encoded_tag.push_back(type_tag & 0x7F); + } + + return encoded_tag; + } + +/* +* DER encode an ASN.1 length field +*/ +secure_vector encode_length(size_t length) + { + secure_vector encoded_length; + if(length <= 127) + encoded_length.push_back(static_cast(length)); + else + { + const size_t top_byte = significant_bytes(length); + + encoded_length.push_back(static_cast(0x80 | top_byte)); + + for(size_t i = sizeof(length) - top_byte; i != sizeof(length); ++i) + encoded_length.push_back(get_byte(i, length)); + } + return encoded_length; + } + +} + +/* +* Return the encoded SEQUENCE/SET +*/ +secure_vector DER_Encoder::DER_Sequence::get_contents() + { + const ASN1_Tag real_class_tag = ASN1_Tag(class_tag | CONSTRUCTED); + + if(type_tag == SET) + { + std::sort(set_contents.begin(), set_contents.end()); + for(size_t i = 0; i != set_contents.size(); ++i) + contents += set_contents[i]; + set_contents.clear(); + } + + secure_vector result; + result += encode_tag(type_tag, real_class_tag); + result += encode_length(contents.size()); + result += contents; + contents.clear(); + + return result; + } + +/* +* Add an encoded value to the SEQUENCE/SET +*/ +void DER_Encoder::DER_Sequence::add_bytes(const byte data[], size_t length) + { + if(type_tag == SET) + set_contents.push_back(secure_vector(data, data + length)); + else + contents += std::make_pair(data, length); + } + +/* +* Return the type and class taggings +*/ +ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const + { + return ASN1_Tag(type_tag | class_tag); + } + +/* +* DER_Sequence Constructor +*/ +DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) : + type_tag(t1), class_tag(t2) + { + } + +/* +* Return the encoded contents +*/ +secure_vector DER_Encoder::get_contents() + { + if(subsequences.size() != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + secure_vector output; + std::swap(output, contents); + return output; + } + +/* +* Start a new ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + subsequences.push_back(DER_Sequence(type_tag, class_tag)); + return (*this); + } + +/* +* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::end_cons() + { + if(subsequences.empty()) + throw Invalid_State("DER_Encoder::end_cons: No such sequence"); + + secure_vector seq = subsequences[subsequences.size()-1].get_contents(); + subsequences.pop_back(); + raw_bytes(seq); + return (*this); + } + +/* +* Start a new ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::start_explicit(u16bit type_no) + { + ASN1_Tag type_tag = static_cast(type_no); + + if(type_tag == SET) + throw Internal_Error("DER_Encoder.start_explicit(SET); cannot perform"); + + return start_cons(type_tag, CONTEXT_SPECIFIC); + } + +/* +* Finish the current ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::end_explicit() + { + return end_cons(); + } + +/* +* Write raw bytes into the stream +*/ +DER_Encoder& DER_Encoder::raw_bytes(const secure_vector& val) + { + return raw_bytes(&val[0], val.size()); + } + +DER_Encoder& DER_Encoder::raw_bytes(const std::vector& val) + { + return raw_bytes(&val[0], val.size()); + } + +/* +* Write raw bytes into the stream +*/ +DER_Encoder& DER_Encoder::raw_bytes(const byte bytes[], size_t length) + { + if(subsequences.size()) + subsequences[subsequences.size()-1].add_bytes(bytes, length); + else + contents += std::make_pair(bytes, length); + + return (*this); + } + +/* +* Encode a NULL object +*/ +DER_Encoder& DER_Encoder::encode_null() + { + return add_object(NULL_TAG, UNIVERSAL, nullptr, 0); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true) + { + return encode(is_true, BOOLEAN, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n) + { + return encode(BigInt(n), INTEGER, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n) + { + return encode(n, INTEGER, UNIVERSAL); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const secure_vector& bytes, + ASN1_Tag real_type) + { + return encode(&bytes[0], bytes.size(), + real_type, real_type, UNIVERSAL); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const std::vector& bytes, + ASN1_Tag real_type) + { + return encode(&bytes[0], bytes.size(), + real_type, real_type, UNIVERSAL); + } + +/* +* Encode this object +*/ +DER_Encoder& DER_Encoder::encode(const byte bytes[], size_t length, + ASN1_Tag real_type) + { + return encode(bytes, length, real_type, real_type, UNIVERSAL); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + byte val = is_true ? 0xFF : 0x00; + return add_object(type_tag, class_tag, &val, 1); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(BigInt(n), type_tag, class_tag); + } + +/* +* DER encode an INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n == 0) + return add_object(type_tag, class_tag, 0); + + bool extra_zero = (n.bits() % 8 == 0); + secure_vector contents(extra_zero + n.bytes()); + BigInt::encode(&contents[extra_zero], n); + if(n < 0) + { + for(size_t i = 0; i != contents.size(); ++i) + contents[i] = ~contents[i]; + for(size_t i = contents.size(); i > 0; --i) + if(++contents[i-1]) + break; + } + + return add_object(type_tag, class_tag, contents); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const secure_vector& bytes, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(&bytes[0], bytes.size(), + real_type, type_tag, class_tag); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const std::vector& bytes, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(&bytes[0], bytes.size(), + real_type, type_tag, class_tag); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const byte bytes[], size_t length, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string"); + + if(real_type == BIT_STRING) + { + secure_vector encoded; + encoded.push_back(0); + encoded += std::make_pair(bytes, length); + return add_object(type_tag, class_tag, encoded); + } + else + return add_object(type_tag, class_tag, bytes, length); + } + +/* +* Conditionally write some values to the stream +*/ +DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec) + { + if(cond) + return raw_bytes(codec.get_contents()); + return (*this); + } + +DER_Encoder& DER_Encoder::encode_if(bool cond, const ASN1_Object& obj) + { + if(cond) + encode(obj); + return (*this); + } + +/* +* Request for an object to encode itself +*/ +DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) + { + obj.encode_into(*this); + return (*this); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const byte rep[], size_t length) + { + secure_vector buffer; + buffer += encode_tag(type_tag, class_tag); + buffer += encode_length(length); + buffer += std::make_pair(rep, length); + + return raw_bytes(buffer); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& rep_str) + { + const byte* rep = reinterpret_cast(rep_str.data()); + const size_t rep_len = rep_str.size(); + return add_object(type_tag, class_tag, rep, rep_len); + } + +/* +* Write the encoding of the byte +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, + ASN1_Tag class_tag, byte rep) + { + return add_object(type_tag, class_tag, &rep, 1); + } + +} diff --git a/src/lib/asn1/der_enc.h b/src/lib/asn1/der_enc.h new file mode 100644 index 000000000..61efb27b1 --- /dev/null +++ b/src/lib/asn1/der_enc.h @@ -0,0 +1,137 @@ +/* +* DER Encoder +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DER_ENCODER_H__ +#define BOTAN_DER_ENCODER_H__ + +#include +#include + +namespace Botan { + +class BigInt; +class ASN1_Object; + +/** +* General DER Encoding Object +*/ +class BOTAN_DLL DER_Encoder + { + public: + secure_vector get_contents(); + + std::vector get_contents_unlocked() + { return unlock(get_contents()); } + + DER_Encoder& start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag = UNIVERSAL); + DER_Encoder& end_cons(); + + DER_Encoder& start_explicit(u16bit type_tag); + DER_Encoder& end_explicit(); + + DER_Encoder& raw_bytes(const byte val[], size_t len); + DER_Encoder& raw_bytes(const secure_vector& val); + DER_Encoder& raw_bytes(const std::vector& val); + + DER_Encoder& encode_null(); + DER_Encoder& encode(bool b); + DER_Encoder& encode(size_t s); + DER_Encoder& encode(const BigInt& n); + DER_Encoder& encode(const secure_vector& v, ASN1_Tag real_type); + DER_Encoder& encode(const std::vector& v, ASN1_Tag real_type); + DER_Encoder& encode(const byte val[], size_t len, ASN1_Tag real_type); + + DER_Encoder& encode(bool b, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(size_t s, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const BigInt& n, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const std::vector& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const secure_vector& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const byte v[], size_t len, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + template + DER_Encoder& encode_optional(const T& value, const T& default_value) + { + if(value != default_value) + encode(value); + return (*this); + } + + template + DER_Encoder& encode_list(const std::vector& values) + { + for(size_t i = 0; i != values.size(); ++i) + encode(values[i]); + return (*this); + } + + DER_Encoder& encode(const ASN1_Object& obj); + DER_Encoder& encode_if(bool pred, DER_Encoder& enc); + DER_Encoder& encode_if(bool pred, const ASN1_Object& obj); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const byte rep[], size_t length); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::vector& rep) + { + return add_object(type_tag, class_tag, &rep[0], rep.size()); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const secure_vector& rep) + { + return add_object(type_tag, class_tag, &rep[0], rep.size()); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& str); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + byte val); + + private: + class DER_Sequence + { + public: + ASN1_Tag tag_of() const; + secure_vector get_contents(); + void add_bytes(const byte[], size_t); + DER_Sequence(ASN1_Tag, ASN1_Tag); + private: + ASN1_Tag type_tag, class_tag; + secure_vector contents; + std::vector< secure_vector > set_contents; + }; + + secure_vector contents; + std::vector subsequences; + }; + +} + +#endif diff --git a/src/lib/asn1/info.txt b/src/lib/asn1/info.txt new file mode 100644 index 000000000..19b75bc4b --- /dev/null +++ b/src/lib/asn1/info.txt @@ -0,0 +1,10 @@ +define ASN1 20131128 + +load_on auto + + +alloc +bigint +filters +oid_lookup + diff --git a/src/lib/asn1/oid_lookup/default.cpp b/src/lib/asn1/oid_lookup/default.cpp new file mode 100644 index 000000000..6904ec0ff --- /dev/null +++ b/src/lib/asn1/oid_lookup/default.cpp @@ -0,0 +1,243 @@ +/* +* OID Registry +* (C) 1999-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace OIDS { + +/* +* Load all of the default OIDs +*/ +void set_defaults() + { + /* Public key types */ + OIDS::add_oidstr("1.2.840.113549.1.1.1", "RSA"); + OIDS::add_oidstr("2.5.8.1.1", "RSA"); // RSA alternate + OIDS::add_oidstr("1.2.840.10040.4.1", "DSA"); + OIDS::add_oidstr("1.2.840.10046.2.1", "DH"); + OIDS::add_oidstr("1.3.6.1.4.1.3029.1.2.1", "ElGamal"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.1.1", "RW"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.1.2", "NR"); + + // X9.62 ecPublicKey, valid for ECDSA and ECDH (RFC 3279 sec 2.3.5) + OIDS::add_oidstr("1.2.840.10045.2.1", "ECDSA"); + + /* + * This is an OID defined for ECDH keys though rarely used for such. + * In this configuration it is accepted on decoding, but not used for + * encoding. You can enable it for encoding by calling + * OIDS::add_str2oid("ECDH", "1.3.132.1.12") + * from your application code. + */ + OIDS::add_oid2str(OID("1.3.132.1.12"), "ECDH"); + + OIDS::add_oidstr("1.2.643.2.2.19", "GOST-34.10"); // RFC 4491 + + /* Ciphers */ + OIDS::add_oidstr("1.3.14.3.2.7", "DES/CBC"); + OIDS::add_oidstr("1.2.840.113549.3.7", "TripleDES/CBC"); + OIDS::add_oidstr("1.2.840.113549.3.2", "RC2/CBC"); + OIDS::add_oidstr("1.2.840.113533.7.66.10", "CAST-128/CBC"); + OIDS::add_oidstr("2.16.840.1.101.3.4.1.2", "AES-128/CBC"); + OIDS::add_oidstr("2.16.840.1.101.3.4.1.22", "AES-192/CBC"); + OIDS::add_oidstr("2.16.840.1.101.3.4.1.42", "AES-256/CBC"); + OIDS::add_oidstr("1.2.410.200004.1.4", "SEED/CBC"); // RFC 4010 + OIDS::add_oidstr("1.3.6.1.4.1.25258.3.1", "Serpent/CBC"); + + /* Hash Functions */ + OIDS::add_oidstr("1.2.840.113549.2.5", "MD5"); + OIDS::add_oidstr("1.3.6.1.4.1.11591.12.2", "Tiger(24,3)"); + + OIDS::add_oidstr("1.3.14.3.2.26", "SHA-160"); + OIDS::add_oidstr("2.16.840.1.101.3.4.2.4", "SHA-224"); + OIDS::add_oidstr("2.16.840.1.101.3.4.2.1", "SHA-256"); + OIDS::add_oidstr("2.16.840.1.101.3.4.2.2", "SHA-384"); + OIDS::add_oidstr("2.16.840.1.101.3.4.2.3", "SHA-512"); + + /* MACs */ + OIDS::add_oidstr("1.2.840.113549.2.7", "HMAC(SHA-160)"); + OIDS::add_oidstr("1.2.840.113549.2.8", "HMAC(SHA-224)"); + OIDS::add_oidstr("1.2.840.113549.2.9", "HMAC(SHA-256)"); + OIDS::add_oidstr("1.2.840.113549.2.10", "HMAC(SHA-384)"); + OIDS::add_oidstr("1.2.840.113549.2.11", "HMAC(SHA-512)"); + + /* Key Wrap */ + OIDS::add_oidstr("1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES"); + OIDS::add_oidstr("1.2.840.113549.1.9.16.3.7", "KeyWrap.RC2"); + OIDS::add_oidstr("1.2.840.113533.7.66.15", "KeyWrap.CAST-128"); + OIDS::add_oidstr("2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128"); + OIDS::add_oidstr("2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192"); + OIDS::add_oidstr("2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256"); + + /* Compression */ + OIDS::add_oidstr("1.2.840.113549.1.9.16.3.8", "Compression.Zlib"); + + /* Public key signature schemes */ + OIDS::add_oidstr("1.2.840.113549.1.1.1", "RSA/EME-PKCS1-v1_5"); + OIDS::add_oidstr("1.2.840.113549.1.1.2", "RSA/EMSA3(MD2)"); + OIDS::add_oidstr("1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)"); + OIDS::add_oidstr("1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)"); + OIDS::add_oidstr("1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)"); + OIDS::add_oidstr("1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)"); + OIDS::add_oidstr("1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)"); + OIDS::add_oidstr("1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)"); + + OIDS::add_oidstr("1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)"); + OIDS::add_oidstr("2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)"); + OIDS::add_oidstr("2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)"); + + OIDS::add_oidstr("0.4.0.127.0.7.1.1.4.1.1", "ECDSA/EMSA1_BSI(SHA-160)"); + OIDS::add_oidstr("0.4.0.127.0.7.1.1.4.1.2", "ECDSA/EMSA1_BSI(SHA-224)"); + OIDS::add_oidstr("0.4.0.127.0.7.1.1.4.1.3", "ECDSA/EMSA1_BSI(SHA-256)"); + OIDS::add_oidstr("0.4.0.127.0.7.1.1.4.1.4", "ECDSA/EMSA1_BSI(SHA-384)"); + OIDS::add_oidstr("0.4.0.127.0.7.1.1.4.1.5", "ECDSA/EMSA1_BSI(SHA-512)"); + OIDS::add_oidstr("0.4.0.127.0.7.1.1.4.1.6", "ECDSA/EMSA1_BSI(RIPEMD-160)"); + + OIDS::add_oidstr("1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)"); + OIDS::add_oidstr("1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)"); + OIDS::add_oidstr("1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)"); + OIDS::add_oidstr("1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)"); + OIDS::add_oidstr("1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)"); + + OIDS::add_oidstr("1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)"); + + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.1.1", "RW/EMSA2(RIPEMD-160)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.1.2", "RW/EMSA2(SHA-160)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.1.3", "RW/EMSA2(SHA-224)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.1.4", "RW/EMSA2(SHA-256)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.1.5", "RW/EMSA2(SHA-384)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.1.6", "RW/EMSA2(SHA-512)"); + + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.2.1", "RW/EMSA4(RIPEMD-160)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.2.2", "RW/EMSA4(SHA-160)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.2.3", "RW/EMSA4(SHA-224)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.2.4", "RW/EMSA4(SHA-256)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.2.5", "RW/EMSA4(SHA-384)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.1.2.6", "RW/EMSA4(SHA-512)"); + + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.2.1.1", "NR/EMSA2(RIPEMD-160)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.2.1.2", "NR/EMSA2(SHA-160)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.2.1.3", "NR/EMSA2(SHA-224)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.2.1.4", "NR/EMSA2(SHA-256)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.2.1.5", "NR/EMSA2(SHA-384)"); + OIDS::add_oidstr("1.3.6.1.4.1.25258.2.2.1.6", "NR/EMSA2(SHA-512)"); + + OIDS::add_oidstr("2.5.4.3", "X520.CommonName"); + OIDS::add_oidstr("2.5.4.4", "X520.Surname"); + OIDS::add_oidstr("2.5.4.5", "X520.SerialNumber"); + OIDS::add_oidstr("2.5.4.6", "X520.Country"); + OIDS::add_oidstr("2.5.4.7", "X520.Locality"); + OIDS::add_oidstr("2.5.4.8", "X520.State"); + OIDS::add_oidstr("2.5.4.10", "X520.Organization"); + OIDS::add_oidstr("2.5.4.11", "X520.OrganizationalUnit"); + OIDS::add_oidstr("2.5.4.12", "X520.Title"); + OIDS::add_oidstr("2.5.4.42", "X520.GivenName"); + OIDS::add_oidstr("2.5.4.43", "X520.Initials"); + OIDS::add_oidstr("2.5.4.44", "X520.GenerationalQualifier"); + OIDS::add_oidstr("2.5.4.46", "X520.DNQualifier"); + OIDS::add_oidstr("2.5.4.65", "X520.Pseudonym"); + + OIDS::add_oidstr("1.2.840.113549.1.5.12", "PKCS5.PBKDF2"); + OIDS::add_oidstr("1.2.840.113549.1.5.1", "PBE-PKCS5v15(MD2,DES/CBC)"); + OIDS::add_oidstr("1.2.840.113549.1.5.4", "PBE-PKCS5v15(MD2,RC2/CBC)"); + OIDS::add_oidstr("1.2.840.113549.1.5.3", "PBE-PKCS5v15(MD5,DES/CBC)"); + OIDS::add_oidstr("1.2.840.113549.1.5.6", "PBE-PKCS5v15(MD5,RC2/CBC)"); + OIDS::add_oidstr("1.2.840.113549.1.5.10", "PBE-PKCS5v15(SHA-160,DES/CBC)"); + OIDS::add_oidstr("1.2.840.113549.1.5.11", "PBE-PKCS5v15(SHA-160,RC2/CBC)"); + OIDS::add_oidstr("1.2.840.113549.1.5.13", "PBE-PKCS5v20"); + + OIDS::add_oidstr("1.2.840.113549.1.9.1", "PKCS9.EmailAddress"); + OIDS::add_oidstr("1.2.840.113549.1.9.2", "PKCS9.UnstructuredName"); + OIDS::add_oidstr("1.2.840.113549.1.9.3", "PKCS9.ContentType"); + OIDS::add_oidstr("1.2.840.113549.1.9.4", "PKCS9.MessageDigest"); + OIDS::add_oidstr("1.2.840.113549.1.9.7", "PKCS9.ChallengePassword"); + OIDS::add_oidstr("1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest"); + + OIDS::add_oidstr("1.2.840.113549.1.7.1", "CMS.DataContent"); + OIDS::add_oidstr("1.2.840.113549.1.7.2", "CMS.SignedData"); + OIDS::add_oidstr("1.2.840.113549.1.7.3", "CMS.EnvelopedData"); + OIDS::add_oidstr("1.2.840.113549.1.7.5", "CMS.DigestedData"); + OIDS::add_oidstr("1.2.840.113549.1.7.6", "CMS.EncryptedData"); + OIDS::add_oidstr("1.2.840.113549.1.9.16.1.2", "CMS.AuthenticatedData"); + OIDS::add_oidstr("1.2.840.113549.1.9.16.1.9", "CMS.CompressedData"); + + OIDS::add_oidstr("2.5.29.14", "X509v3.SubjectKeyIdentifier"); + OIDS::add_oidstr("2.5.29.15", "X509v3.KeyUsage"); + OIDS::add_oidstr("2.5.29.17", "X509v3.SubjectAlternativeName"); + OIDS::add_oidstr("2.5.29.18", "X509v3.IssuerAlternativeName"); + OIDS::add_oidstr("2.5.29.19", "X509v3.BasicConstraints"); + OIDS::add_oidstr("2.5.29.20", "X509v3.CRLNumber"); + OIDS::add_oidstr("2.5.29.21", "X509v3.ReasonCode"); + OIDS::add_oidstr("2.5.29.23", "X509v3.HoldInstructionCode"); + OIDS::add_oidstr("2.5.29.24", "X509v3.InvalidityDate"); + OIDS::add_oidstr("2.5.29.31", "X509v3.CRLDistributionPoints"); + OIDS::add_oidstr("2.5.29.32", "X509v3.CertificatePolicies"); + OIDS::add_oidstr("2.5.29.35", "X509v3.AuthorityKeyIdentifier"); + OIDS::add_oidstr("2.5.29.36", "X509v3.PolicyConstraints"); + OIDS::add_oidstr("2.5.29.37", "X509v3.ExtendedKeyUsage"); + OIDS::add_oidstr("1.3.6.1.5.5.7.1.1", "PKIX.AuthorityInformationAccess"); + + OIDS::add_oidstr("2.5.29.32.0", "X509v3.AnyPolicy"); + + OIDS::add_oidstr("1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping"); + OIDS::add_oidstr("1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning"); + + OIDS::add_oidstr("1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr"); + + OIDS::add_oidstr("1.3.6.1.5.5.7.48.1", "PKIX.OCSP"); + OIDS::add_oidstr("1.3.6.1.5.5.7.48.1.1", "PKIX.OCSP.BasicResponse"); + + /* ECC domain parameters */ + OIDS::add_oidstr("1.3.132.0.6", "secp112r1"); + OIDS::add_oidstr("1.3.132.0.7", "secp112r2"); + OIDS::add_oidstr("1.3.132.0.8", "secp160r1"); + OIDS::add_oidstr("1.3.132.0.9", "secp160k1"); + OIDS::add_oidstr("1.3.132.0.10", "secp256k1"); + OIDS::add_oidstr("1.3.132.0.28", "secp128r1"); + OIDS::add_oidstr("1.3.132.0.29", "secp128r2"); + OIDS::add_oidstr("1.3.132.0.30", "secp160r2"); + OIDS::add_oidstr("1.3.132.0.31", "secp192k1"); + OIDS::add_oidstr("1.3.132.0.32", "secp224k1"); + OIDS::add_oidstr("1.3.132.0.33", "secp224r1"); + OIDS::add_oidstr("1.3.132.0.34", "secp384r1"); + OIDS::add_oidstr("1.3.132.0.35", "secp521r1"); + + OIDS::add_oidstr("1.2.840.10045.3.1.1", "secp192r1"); + OIDS::add_oidstr("1.2.840.10045.3.1.2", "x962_p192v2"); + OIDS::add_oidstr("1.2.840.10045.3.1.3", "x962_p192v3"); + OIDS::add_oidstr("1.2.840.10045.3.1.4", "x962_p239v1"); + OIDS::add_oidstr("1.2.840.10045.3.1.5", "x962_p239v2"); + OIDS::add_oidstr("1.2.840.10045.3.1.6", "x962_p239v3"); + OIDS::add_oidstr("1.2.840.10045.3.1.7", "secp256r1"); + + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.1", "brainpool160r1"); + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.3", "brainpool192r1"); + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.5", "brainpool224r1"); + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.7", "brainpool256r1"); + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.9", "brainpool320r1"); + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.11", "brainpool384r1"); + OIDS::add_oidstr("1.3.36.3.3.2.8.1.1.13", "brainpool512r1"); + + OIDS::add_oidstr("1.2.643.2.2.35.1", "gost_256A"); + OIDS::add_oidstr("1.2.643.2.2.36.0", "gost_256A"); + + /* CVC */ + OIDS::add_oidstr("0.4.0.127.0.7.3.1.2.1", "CertificateHolderAuthorizationTemplate"); + } + +} + +} diff --git a/src/lib/asn1/oid_lookup/info.txt b/src/lib/asn1/oid_lookup/info.txt new file mode 100644 index 000000000..57b51e7d8 --- /dev/null +++ b/src/lib/asn1/oid_lookup/info.txt @@ -0,0 +1,5 @@ +define OID_LOOKUP 20131128 + + +asn1 + diff --git a/src/lib/asn1/oid_lookup/oids.cpp b/src/lib/asn1/oid_lookup/oids.cpp new file mode 100644 index 000000000..54944d1a2 --- /dev/null +++ b/src/lib/asn1/oid_lookup/oids.cpp @@ -0,0 +1,133 @@ +/* +* OID Registry +* (C) 1999-2008,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace OIDS { + +namespace { + +class OID_Map + { + public: + void add_oid(const OID& oid, const std::string& str) + { + add_str2oid(oid, str); + add_oid2str(oid, str); + } + + void add_str2oid(const OID& oid, const std::string& str) + { + std::lock_guard lock(m_mutex); + auto i = m_str2oid.find(str); + if(i == m_str2oid.end()) + m_str2oid.insert(std::make_pair(str, oid)); + } + + void add_oid2str(const OID& oid, const std::string& str) + { + std::lock_guard lock(m_mutex); + auto i = m_oid2str.find(oid); + if(i == m_oid2str.end()) + m_oid2str.insert(std::make_pair(oid, str)); + } + + std::string lookup(const OID& oid) + { + std::lock_guard lock(m_mutex); + + auto i = m_oid2str.find(oid); + if(i != m_oid2str.end()) + return i->second; + + return ""; + } + + OID lookup(const std::string& str) + { + std::lock_guard lock(m_mutex); + + auto i = m_str2oid.find(str); + if(i != m_str2oid.end()) + return i->second; + + // Try to parse as plain OID + try + { + return OID(str); + } + catch(...) {} + + throw Lookup_Error("No object identifier found for " + str); + } + + bool have_oid(const std::string& str) + { + std::lock_guard lock(m_mutex); + return m_str2oid.find(str) != m_str2oid.end(); + } + + private: + std::mutex m_mutex; + std::map m_str2oid; + std::map m_oid2str; + }; + +OID_Map& global_oid_map() + { + static OID_Map map; + return map; + } + +} + +void add_oid(const OID& oid, const std::string& name) + { + global_oid_map().add_oid(oid, name); + } + +void add_oidstr(const char* oidstr, const char* name) + { + add_oid(OID(oidstr), name); + } + +void add_oid2str(const OID& oid, const std::string& name) + { + global_oid_map().add_oid2str(oid, name); + } + +void add_str2oid(const OID& oid, const std::string& name) + { + global_oid_map().add_oid2str(oid, name); + } + +std::string lookup(const OID& oid) + { + return global_oid_map().lookup(oid); + } + +OID lookup(const std::string& name) + { + return global_oid_map().lookup(name); + } + +bool have_oid(const std::string& name) + { + return global_oid_map().have_oid(name); + } + +bool name_of(const OID& oid, const std::string& name) + { + return (oid == lookup(name)); + } + +} + +} diff --git a/src/lib/asn1/oid_lookup/oids.h b/src/lib/asn1/oid_lookup/oids.h new file mode 100644 index 000000000..27533202f --- /dev/null +++ b/src/lib/asn1/oid_lookup/oids.h @@ -0,0 +1,65 @@ +/* +* OID Registry +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OIDS_H__ +#define BOTAN_OIDS_H__ + +#include + +namespace Botan { + +namespace OIDS { + +/** +* Register an OID to string mapping. +* @param oid the oid to register +* @param name the name to be associated with the oid +*/ +BOTAN_DLL void add_oid(const OID& oid, const std::string& name); + +BOTAN_DLL void add_oid2str(const OID& oid, const std::string& name); +BOTAN_DLL void add_str2oid(const OID& oid, const std::string& name); + +BOTAN_DLL void add_oidstr(const char* oidstr, const char* name); + +/** +* See if an OID exists in the internal table. +* @param oid the oid to check for +* @return true if the oid is registered +*/ +BOTAN_DLL bool have_oid(const std::string& oid); + +/** +* Resolve an OID +* @param oid the OID to look up +* @return name associated with this OID +*/ +BOTAN_DLL std::string lookup(const OID& oid); + +/** +* Find the OID to a name. The lookup will be performed in the +* general OID section of the configuration. +* @param name the name to resolve +* @return OID associated with the specified name +*/ +BOTAN_DLL OID lookup(const std::string& name); + +/** +* Tests whether the specified OID stands for the specified name. +* @param oid the OID to check +* @param name the name to check +* @return true if the specified OID stands for the specified name +*/ +BOTAN_DLL bool name_of(const OID& oid, const std::string& name); + +BOTAN_DLL void set_defaults(); + +} + +} + +#endif diff --git a/src/lib/asn1/x509_dn.cpp b/src/lib/asn1/x509_dn.cpp new file mode 100644 index 000000000..672e18f18 --- /dev/null +++ b/src/lib/asn1/x509_dn.cpp @@ -0,0 +1,311 @@ +/* +* X509_DN +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an empty X509_DN +*/ +X509_DN::X509_DN() + { + } + +/* +* Create an X509_DN +*/ +X509_DN::X509_DN(const std::multimap& args) + { + for(auto i = args.begin(); i != args.end(); ++i) + add_attribute(i->first, i->second); + } + +/* +* Create an X509_DN +*/ +X509_DN::X509_DN(const std::multimap& args) + { + for(auto i = args.begin(); i != args.end(); ++i) + add_attribute(OIDS::lookup(i->first), i->second); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const std::string& type, + const std::string& str) + { + OID oid = OIDS::lookup(type); + add_attribute(oid, str); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const OID& oid, const std::string& str) + { + if(str == "") + return; + + auto range = dn_info.equal_range(oid); + for(auto i = range.first; i != range.second; ++i) + if(i->second.value() == str) + return; + + multimap_insert(dn_info, oid, ASN1_String(str)); + dn_bits.clear(); + } + +/* +* Get the attributes of this X509_DN +*/ +std::multimap X509_DN::get_attributes() const + { + std::multimap retval; + for(auto i = dn_info.begin(); i != dn_info.end(); ++i) + multimap_insert(retval, i->first, i->second.value()); + return retval; + } + +/* +* Get the contents of this X.500 Name +*/ +std::multimap X509_DN::contents() const + { + std::multimap retval; + for(auto i = dn_info.begin(); i != dn_info.end(); ++i) + multimap_insert(retval, OIDS::lookup(i->first), i->second.value()); + return retval; + } + +/* +* Get a single attribute type +*/ +std::vector X509_DN::get_attribute(const std::string& attr) const + { + const OID oid = OIDS::lookup(deref_info_field(attr)); + + auto range = dn_info.equal_range(oid); + + std::vector values; + for(auto i = range.first; i != range.second; ++i) + values.push_back(i->second.value()); + return values; + } + +/* +* Return the BER encoded data, if any +*/ +std::vector X509_DN::get_bits() const + { + return dn_bits; + } + +/* +* Deref aliases in a subject/issuer info request +*/ +std::string X509_DN::deref_info_field(const std::string& info) + { + if(info == "Name" || info == "CommonName") return "X520.CommonName"; + if(info == "SerialNumber") return "X520.SerialNumber"; + if(info == "Country") return "X520.Country"; + if(info == "Organization") return "X520.Organization"; + if(info == "Organizational Unit" || info == "OrgUnit") + return "X520.OrganizationalUnit"; + if(info == "Locality") return "X520.Locality"; + if(info == "State" || info == "Province") return "X520.State"; + if(info == "Email") return "RFC822"; + return info; + } + +/* +* Compare two X509_DNs for equality +*/ +bool operator==(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() != attr2.size()) return false; + + auto p1 = attr1.begin(); + auto p2 = attr2.begin(); + + while(true) + { + if(p1 == attr1.end() && p2 == attr2.end()) + break; + if(p1 == attr1.end()) return false; + if(p2 == attr2.end()) return false; + if(p1->first != p2->first) return false; + if(!x500_name_cmp(p1->second, p2->second)) + return false; + ++p1; + ++p2; + } + return true; + } + +/* +* Compare two X509_DNs for inequality +*/ +bool operator!=(const X509_DN& dn1, const X509_DN& dn2) + { + return !(dn1 == dn2); + } + +/* +* Induce an arbitrary ordering on DNs +*/ +bool operator<(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() < attr2.size()) return true; + if(attr1.size() > attr2.size()) return false; + + for(auto p1 = attr1.begin(); p1 != attr1.end(); ++p1) + { + auto p2 = attr2.find(p1->first); + if(p2 == attr2.end()) return false; + if(p1->second > p2->second) return false; + if(p1->second < p2->second) return true; + } + return false; + } + +namespace { + +/* +* DER encode a RelativeDistinguishedName +*/ +void do_ava(DER_Encoder& encoder, + const std::multimap& dn_info, + ASN1_Tag string_type, const std::string& oid_str, + bool must_exist = false) + { + const OID oid = OIDS::lookup(oid_str); + const bool exists = (dn_info.find(oid) != dn_info.end()); + + if(!exists && must_exist) + throw Encoding_Error("X509_DN: No entry for " + oid_str); + if(!exists) return; + + auto range = dn_info.equal_range(oid); + + for(auto i = range.first; i != range.second; ++i) + { + encoder.start_cons(SET) + .start_cons(SEQUENCE) + .encode(oid) + .encode(ASN1_String(i->second, string_type)) + .end_cons() + .end_cons(); + } + } + +} + +/* +* DER encode a DistinguishedName +*/ +void X509_DN::encode_into(DER_Encoder& der) const + { + auto dn_info = get_attributes(); + + der.start_cons(SEQUENCE); + + if(!dn_bits.empty()) + der.raw_bytes(dn_bits); + else + { + do_ava(der, dn_info, PRINTABLE_STRING, "X520.Country"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.State"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.Locality"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.Organization"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.OrganizationalUnit"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.CommonName"); + do_ava(der, dn_info, PRINTABLE_STRING, "X520.SerialNumber"); + } + + der.end_cons(); + } + +/* +* Decode a BER encoded DistinguishedName +*/ +void X509_DN::decode_from(BER_Decoder& source) + { + std::vector bits; + + source.start_cons(SEQUENCE) + .raw_bytes(bits) + .end_cons(); + + BER_Decoder sequence(bits); + + while(sequence.more_items()) + { + BER_Decoder rdn = sequence.start_cons(SET); + + while(rdn.more_items()) + { + OID oid; + ASN1_String str; + + rdn.start_cons(SEQUENCE) + .decode(oid) + .decode(str) + .verify_end() + .end_cons(); + + add_attribute(oid, str.value()); + } + } + + dn_bits = bits; + } + +namespace { + +std::string to_short_form(const std::string& long_id) + { + if(long_id == "X520.CommonName") + return "CN"; + + if(long_id == "X520.Organization") + return "O"; + + if(long_id == "X520.OrganizationalUnit") + return "OU"; + + return long_id; + } + +} + +std::ostream& operator<<(std::ostream& out, const X509_DN& dn) + { + std::multimap contents = dn.contents(); + + for(std::multimap::const_iterator i = contents.begin(); + i != contents.end(); ++i) + { + out << to_short_form(i->first) << "=" << i->second << ' '; + } + return out; + } + +} diff --git a/src/lib/asn1/x509_dn.h b/src/lib/asn1/x509_dn.h new file mode 100644 index 000000000..e37fe6627 --- /dev/null +++ b/src/lib/asn1/x509_dn.h @@ -0,0 +1,56 @@ +/* +* X.509 Distinguished Name +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_DN_H__ +#define BOTAN_X509_DN_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Distinguished Name +*/ +class BOTAN_DLL X509_DN : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::multimap get_attributes() const; + std::vector get_attribute(const std::string&) const; + + std::multimap contents() const; + + void add_attribute(const std::string&, const std::string&); + void add_attribute(const OID&, const std::string&); + + static std::string deref_info_field(const std::string&); + + std::vector get_bits() const; + + X509_DN(); + X509_DN(const std::multimap&); + X509_DN(const std::multimap&); + private: + std::multimap dn_info; + std::vector dn_bits; + }; + +bool BOTAN_DLL operator==(const X509_DN&, const X509_DN&); +bool BOTAN_DLL operator!=(const X509_DN&, const X509_DN&); +bool BOTAN_DLL operator<(const X509_DN&, const X509_DN&); + +BOTAN_DLL std::ostream& operator<<(std::ostream& out, const X509_DN& dn); + +} + +#endif diff --git a/src/lib/benchmark/benchmark.cpp b/src/lib/benchmark/benchmark.cpp new file mode 100644 index 000000000..396670168 --- /dev/null +++ b/src/lib/benchmark/benchmark.cpp @@ -0,0 +1,161 @@ +/* +* Runtime benchmarking +* (C) 2008-2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +double time_op(std::chrono::nanoseconds runtime, std::function op) + { + std::chrono::nanoseconds time_used(0); + size_t reps = 0; + + auto start = std::chrono::high_resolution_clock::now(); + + while(time_used < runtime) + { + op(); + ++reps; + time_used = std::chrono::high_resolution_clock::now() - start; + } + + const u64bit nsec_used = std::chrono::duration_cast(time_used).count(); + + const double seconds_used = static_cast(nsec_used) / 1000000000; + + return reps / seconds_used; // ie, return ops per second + } + +std::map +time_algorithm_ops(const std::string& name, + Algorithm_Factory& af, + const std::string& provider, + RandomNumberGenerator& rng, + std::chrono::nanoseconds runtime, + size_t buf_size) + { + const size_t Mebibyte = 1024*1024; + + secure_vector buffer(buf_size * 1024); + rng.randomize(&buffer[0], buffer.size()); + + const double mb_mult = buffer.size() / static_cast(Mebibyte); + + if(const BlockCipher* proto = af.prototype_block_cipher(name, provider)) + { + std::unique_ptr bc(proto->clone()); + + const SymmetricKey key(rng, bc->maximum_keylength()); + + return std::map({ + { "key schedule", time_op(runtime / 8, [&]() { bc->set_key(key); }) }, + { "encrypt", mb_mult * time_op(runtime / 2, [&]() { bc->encrypt(buffer); }) }, + { "decrypt", mb_mult * time_op(runtime / 2, [&]() { bc->decrypt(buffer); }) }, + }); + } + else if(const StreamCipher* proto = af.prototype_stream_cipher(name, provider)) + { + std::unique_ptr sc(proto->clone()); + + const SymmetricKey key(rng, sc->maximum_keylength()); + + return std::map({ + { "key schedule", time_op(runtime / 8, [&]() { sc->set_key(key); }) }, + { "", mb_mult * time_op(runtime, [&]() { sc->encipher(buffer); }) }, + }); + } + else if(const HashFunction* proto = af.prototype_hash_function(name, provider)) + { + std::unique_ptr h(proto->clone()); + + return std::map({ + { "", mb_mult * time_op(runtime, [&]() { h->update(buffer); }) }, + }); + } + else if(const MessageAuthenticationCode* proto = af.prototype_mac(name, provider)) + { + std::unique_ptr mac(proto->clone()); + + const SymmetricKey key(rng, mac->maximum_keylength()); + + return std::map({ + { "key schedule", time_op(runtime / 8, [&]() { mac->set_key(key); }) }, + { "", mb_mult * time_op(runtime, [&]() { mac->update(buffer); }) }, + }); + } + else + { + std::unique_ptr enc(get_aead(name, ENCRYPTION)); + std::unique_ptr dec(get_aead(name, DECRYPTION)); + + if(enc && dec) + { + const SymmetricKey key(rng, enc->maximum_keylength()); + + return std::map({ + { "key schedule", time_op(runtime / 4, [&]() { enc->set_key(key); dec->set_key(key); }) / 2 }, + { "encrypt", mb_mult * time_op(runtime / 2, [&]() { enc->update(buffer, 0); buffer.resize(buf_size*1024); }) }, + { "decrypt", mb_mult * time_op(runtime / 2, [&]() { dec->update(buffer, 0); buffer.resize(buf_size*1024); }) }, + }); + } + } + + return std::map(); + } + +namespace { + +double find_first_in(const std::map& m, + const std::vector& keys) + { + for(auto key : keys) + { + auto i = m.find(key); + if(i != m.end()) + return i->second; + } + + throw std::runtime_error("algorithm_factory no usable keys found in result"); + } + +} + +std::map +algorithm_benchmark(const std::string& name, + Algorithm_Factory& af, + RandomNumberGenerator& rng, + std::chrono::milliseconds milliseconds, + size_t buf_size) + { + const std::vector providers = af.providers_of(name); + + std::map all_results; // provider -> ops/sec + + if(!providers.empty()) + { + const std::chrono::nanoseconds ns_per_provider = milliseconds / providers.size(); + + for(auto provider : providers) + { + auto results = time_algorithm_ops(name, af, provider, rng, ns_per_provider, buf_size); + all_results[provider] = find_first_in(results, { "", "update", "encrypt" }); + } + } + + return all_results; + } + +} diff --git a/src/lib/benchmark/benchmark.h b/src/lib/benchmark/benchmark.h new file mode 100644 index 000000000..40784a767 --- /dev/null +++ b/src/lib/benchmark/benchmark.h @@ -0,0 +1,58 @@ +/* +* Runtime benchmarking +* (C) 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RUNTIME_BENCHMARK_H__ +#define BOTAN_RUNTIME_BENCHMARK_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Time aspects of an algorithm/provider +* @param name the name of the algorithm to test +* @param af the algorithm factory used to create objects +* @param provider the provider to use +* @param rng the rng to use to generate random inputs +* @param runtime total time for the benchmark to run +* @param buf_size size of buffer to benchmark against, in KiB +* @return results a map from op type to operations per second +*/ +std::map +BOTAN_DLL time_algorithm_ops(const std::string& name, + Algorithm_Factory& af, + const std::string& provider, + RandomNumberGenerator& rng, + std::chrono::nanoseconds runtime, + size_t buf_size); + +/** +* Algorithm benchmark +* @param name the name of the algorithm to test (cipher, hash, or MAC) +* @param af the algorithm factory used to create objects +* @param rng the rng to use to generate random inputs +* @param milliseconds total time for the benchmark to run +* @param buf_size size of buffer to benchmark against, in KiB +* @return results a map from provider to speed in mebibytes per second +*/ +std::map +BOTAN_DLL algorithm_benchmark(const std::string& name, + Algorithm_Factory& af, + RandomNumberGenerator& rng, + std::chrono::milliseconds milliseconds, + size_t buf_size); + +double BOTAN_DLL +time_op(std::chrono::nanoseconds runtime, std::function op); + +} + +#endif diff --git a/src/lib/benchmark/info.txt b/src/lib/benchmark/info.txt new file mode 100644 index 000000000..264811d99 --- /dev/null +++ b/src/lib/benchmark/info.txt @@ -0,0 +1,11 @@ +define RUNTIME_BENCHMARKING 20131128 + + +algo_factory +block +algo_base +hash +mac +rng +stream + diff --git a/src/lib/block/aes/aes.cpp b/src/lib/block/aes/aes.cpp new file mode 100644 index 000000000..f8d632c44 --- /dev/null +++ b/src/lib/block/aes/aes.cpp @@ -0,0 +1,752 @@ +/* +* AES +* (C) 1999-2010 Jack Lloyd +* +* Based on the public domain reference implemenation +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +const byte SE[256] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16 }; + +const byte SD[256] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D }; + +const u32bit TE[1024] = { + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, + 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, + 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D, + 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, + 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, + 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4, + 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, + 0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, + 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E, + 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, + 0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, + 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46, + 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, + 0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, + 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE, + 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, + 0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, + 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2, + 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, + 0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, + 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256, + 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, + 0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, + 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA, + 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, + 0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, + 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42, + 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, + 0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, + 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22, + 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, + 0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, + 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, 0xA5C66363, 0x84F87C7C, + 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, + 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, + 0xE64DABAB, 0x9AEC7676, 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, + 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, 0xEC41ADAD, 0x67B3D4D4, + 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, + 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, + 0x02F5F7F7, 0x4F83CCCC, 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, + 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, 0x0C080404, 0x5295C7C7, + 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, + 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, + 0xCD7FB2B2, 0x9FEA7575, 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, + 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, 0xF6A45252, 0x4D763B3B, + 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, + 0xC879B1B1, 0xEDB65B5B, 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, + 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, 0x6BBBD0D0, 0x2AC5EFEF, + 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, + 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, + 0xBA259F9F, 0xE34BA8A8, 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, + 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, 0xDF63BCBC, 0xC177B6B6, + 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, + 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, + 0xCC884444, 0x392E1717, 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, + 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, 0xA0C06060, 0x98198181, + 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, + 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, + 0x1D160B0B, 0x76ADDBDB, 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, + 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, 0x5D9FC2C2, 0x6EBDD3D3, + 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, + 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, + 0xD29C4E4E, 0xE049A9A9, 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, + 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, 0xD56FBABA, 0x88F07878, + 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, + 0x860D8B8B, 0x850F8A8A, 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, + 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, 0xA3C26161, 0x5F6A3535, + 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, + 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, + 0x89078E8E, 0xA7339494, 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, + 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, 0x8F038C8C, 0xF859A1A1, + 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, + 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, + 0xD66DBBBB, 0x3A2C1616, 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, + 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, 0x30506030, 0x01030201, + 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, + 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, + 0x47C98E47, 0xF00BFBF0, 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, + 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, 0xB7C275B7, 0xFD1CE1FD, + 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, + 0x31536231, 0x153F2A15, 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, + 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, 0x07090E07, 0x12362412, + 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, + 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, + 0x5AEEB45A, 0xA0FB5BA0, 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, + 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, 0x53F5A653, 0xD168B9D1, + 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, + 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, + 0x58E8B058, 0xCF4A85CF, 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, + 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, 0x45CF8A45, 0xF910E9F9, + 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, + 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, + 0x38487038, 0xF504F1F5, 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, + 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, 0xCD4C81CD, 0x0C14180C, + 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, + 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, + 0x192B3219, 0x7395E673, 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, + 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, 0x46CA8C46, 0xEE29C7EE, + 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, + 0x246C4824, 0x5CE4B85C, 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, + 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, 0xE732D5E7, 0xC8438BC8, + 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, + 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, + 0xAEE947AE, 0x08181008, 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, + 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, 0xE823CBE8, 0xDD7CA1DD, + 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, + 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, + 0xF601F7F6, 0x0E121C0E, 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, + 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, 0xE138D9E1, 0xF813EBF8, + 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, + 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, + 0x28785028, 0xDF7AA5DF, 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, + 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, 0x41C38241, 0x99B02999, + 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16, + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, + 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, + 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F, + 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, + 0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, + 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451, + 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, + 0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, + 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D, + 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, + 0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, + 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D, + 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, + 0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, + 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D, + 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, + 0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, + 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255, + 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, + 0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, + 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664, + 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, + 0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, + 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC, + 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, + 0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, + 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C, + 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, + 0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, + 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C, + 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, + 0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, + 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C }; + +const u32bit TD[1024] = { + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, + 0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, + 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, 0xDEB15A49, 0x25BA1B67, + 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, + 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, + 0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, + 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, 0x63DF4A18, 0xE51A3182, + 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, + 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, + 0xE31F8F57, 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, + 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, 0xA779B492, + 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, + 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, + 0x5E719F06, 0xBD6E1051, 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, + 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997, + 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, + 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, + 0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, + 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F, + 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, + 0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, + 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, 0x8B432976, 0xCB23C6DC, + 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, + 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, + 0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, + 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, 0x87494EC7, 0xD938D1C1, + 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, + 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, + 0x2E39F75E, 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, + 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, 0x6E5918F4, + 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, + 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, + 0xC6A59430, 0x35A266C0, 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, + 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D, + 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, + 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, + 0xE9105633, 0x6DD64713, 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, + 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F, + 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, + 0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, + 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742, 0x5051F4A7, 0x537E4165, + 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, + 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, + 0x80263544, 0x8FB562A3, 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, + 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, 0xE7038F5F, 0x9515929C, + 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, + 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, + 0x66C920AC, 0xB47DCE3A, 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, + 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, 0x58704868, 0x198F45FD, + 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, + 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, + 0xBA02036A, 0x5CED1682, 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, + 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, 0x9D342E53, 0xA0A2F355, + 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, + 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, + 0x6F0406D4, 0xFF605015, 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, + 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, 0x47A17C0A, 0xE97C420F, + 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, + 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, + 0xD19B5B54, 0x3A24362E, 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, + 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, 0x0AE293BA, 0xE5C0A02A, + 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, + 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, + 0xC544663B, 0x345BFB7E, 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, + 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, 0x7D854A24, 0xF8D2BB3D, + 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, + 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, + 0xD8567D2C, 0xEF223390, 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, + 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, 0xE42C3A9D, 0x0D507892, + 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, + 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, + 0x6EE89C63, 0x7BDB3BBB, 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, + 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, 0xD9BAE79B, 0xCE4A6F36, + 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, + 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, + 0x0E7FCD50, 0x2F1791F6, 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, + 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, 0x049D5EEA, 0x5D018C35, + 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, + 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, + 0xEDE11CE5, 0x3C7A47B1, 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, + 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, 0x81CAAFF3, 0x3EB968C4, + 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, + 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, + 0x74486C5C, 0x42D0B857, 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, + 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, 0xFA552030, 0x6DF6AD76, + 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, + 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, + 0x97A38D46, 0xF9C66BD3, 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, + 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, 0x896A75C2, 0x7978F48E, + 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, + 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, + 0xA01CFE81, 0x2B94F908, 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, + 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, 0x2807B2EB, 0xC2032FB5, + 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, + 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, + 0x621FD134, 0xFE8AC4A6, 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, + 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, 0x8AF93E21, 0x063D96DD, + 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, + 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, + 0x5B38E719, 0xEEDB79C8, 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, + 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, 0xFFFBFD0E, 0x38560F85, + 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, + 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, + 0x4B695A77, 0x1A161C12, 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, + 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, 0x198557F1, 0x074CAF75, + 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, + 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, + 0x22401397, 0x112084C6, 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, + 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, 0x166C2BB3, 0xB999A970, + 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, + 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, + 0x8E26DAB7, 0xBFA43FAD, 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, + 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, 0x80BE9F5D, 0x937C69D0, + 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, + 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, + 0xCF0821BC, 0xE8E6EF15, 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, + 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, 0xBC37744E, 0xCAA6FC82, + 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, + 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, + 0x1FB8C12C, 0x517F4665, 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, + 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, 0x618C9AD7, 0x0C7A37A1, + 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, + 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, + 0x6F14DF3D, 0xDB867844, 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, + 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, 0x017139A8, 0xB3DE080C, + 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8, + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, + 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, + 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, + 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, + 0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, + 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5, + 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, + 0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, + 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7, + 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, + 0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, + 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6, + 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, + 0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, + 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93, + 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, + 0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, + 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB, + 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, + 0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, + 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9, + 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, + 0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, + 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E, + 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, + 0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, + 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43, + 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, + 0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, + 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55, + 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, + 0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, + 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 }; + +/* +* AES Encryption +*/ +void aes_encrypt_n(const byte in[], byte out[], + size_t blocks, + const secure_vector& EK, + const secure_vector& ME) + { + BOTAN_ASSERT(EK.size() && ME.size() == 16, "Key was set"); + + const size_t BLOCK_SIZE = 16; + + const u32bit* TE0 = TE; + const u32bit* TE1 = TE + 256; + const u32bit* TE2 = TE + 512; + const u32bit* TE3 = TE + 768; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit T0 = load_be(in, 0) ^ EK[0]; + u32bit T1 = load_be(in, 1) ^ EK[1]; + u32bit T2 = load_be(in, 2) ^ EK[2]; + u32bit T3 = load_be(in, 3) ^ EK[3]; + + /* Use only the first 256 entries of the TE table and do the + * rotations directly in the code. This reduces the number of + * cache lines potentially used in the first round from 64 to 16 + * (assuming a typical 64 byte cache line), which makes timing + * attacks a little harder; the first round is particularly + * vulnerable. + */ + + u32bit B0 = TE[get_byte(0, T0)] ^ + rotate_right(TE[get_byte(1, T1)], 8) ^ + rotate_right(TE[get_byte(2, T2)], 16) ^ + rotate_right(TE[get_byte(3, T3)], 24) ^ EK[4]; + + u32bit B1 = TE[get_byte(0, T1)] ^ + rotate_right(TE[get_byte(1, T2)], 8) ^ + rotate_right(TE[get_byte(2, T3)], 16) ^ + rotate_right(TE[get_byte(3, T0)], 24) ^ EK[5]; + + u32bit B2 = TE[get_byte(0, T2)] ^ + rotate_right(TE[get_byte(1, T3)], 8) ^ + rotate_right(TE[get_byte(2, T0)], 16) ^ + rotate_right(TE[get_byte(3, T1)], 24) ^ EK[6]; + + u32bit B3 = TE[get_byte(0, T3)] ^ + rotate_right(TE[get_byte(1, T0)], 8) ^ + rotate_right(TE[get_byte(2, T1)], 16) ^ + rotate_right(TE[get_byte(3, T2)], 24) ^ EK[7]; + + for(size_t r = 2*4; r < EK.size(); r += 2*4) + { + T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(1, B1)] ^ + TE2[get_byte(2, B2)] ^ TE3[get_byte(3, B3)] ^ EK[r]; + T1 = TE0[get_byte(0, B1)] ^ TE1[get_byte(1, B2)] ^ + TE2[get_byte(2, B3)] ^ TE3[get_byte(3, B0)] ^ EK[r+1]; + T2 = TE0[get_byte(0, B2)] ^ TE1[get_byte(1, B3)] ^ + TE2[get_byte(2, B0)] ^ TE3[get_byte(3, B1)] ^ EK[r+2]; + T3 = TE0[get_byte(0, B3)] ^ TE1[get_byte(1, B0)] ^ + TE2[get_byte(2, B1)] ^ TE3[get_byte(3, B2)] ^ EK[r+3]; + + B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(1, T1)] ^ + TE2[get_byte(2, T2)] ^ TE3[get_byte(3, T3)] ^ EK[r+4]; + B1 = TE0[get_byte(0, T1)] ^ TE1[get_byte(1, T2)] ^ + TE2[get_byte(2, T3)] ^ TE3[get_byte(3, T0)] ^ EK[r+5]; + B2 = TE0[get_byte(0, T2)] ^ TE1[get_byte(1, T3)] ^ + TE2[get_byte(2, T0)] ^ TE3[get_byte(3, T1)] ^ EK[r+6]; + B3 = TE0[get_byte(0, T3)] ^ TE1[get_byte(1, T0)] ^ + TE2[get_byte(2, T1)] ^ TE3[get_byte(3, T2)] ^ EK[r+7]; + } + + /* + Joseph Bonneau and Ilya Mironov's paper "Cache-Collision Timing + Attacks Against AES" describes an attack that can recover AES + keys with as few as 2**13 samples. + + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.88.4753 + + They recommend using a byte-wide table, which still allows an attack + but increases the samples required from 2**13 to 2**25: + + """In addition to OpenSSL v. 0.9.8.(a), which was used in our + experiments, the AES implementations of Crypto++ 5.2.1 and + LibTomCrypt 1.09 use the original Rijndael C implementation with + very few changes and are highly vulnerable. The AES implementations + in libgcrypt v. 1.2.2 and Botan v. 1.4.2 are also vulnerable, but + use a smaller byte-wide final table which lessens the effectiveness + of the attacks.""" + */ + + out[ 0] = SE[get_byte(0, B0)] ^ ME[0]; + out[ 1] = SE[get_byte(1, B1)] ^ ME[1]; + out[ 2] = SE[get_byte(2, B2)] ^ ME[2]; + out[ 3] = SE[get_byte(3, B3)] ^ ME[3]; + out[ 4] = SE[get_byte(0, B1)] ^ ME[4]; + out[ 5] = SE[get_byte(1, B2)] ^ ME[5]; + out[ 6] = SE[get_byte(2, B3)] ^ ME[6]; + out[ 7] = SE[get_byte(3, B0)] ^ ME[7]; + out[ 8] = SE[get_byte(0, B2)] ^ ME[8]; + out[ 9] = SE[get_byte(1, B3)] ^ ME[9]; + out[10] = SE[get_byte(2, B0)] ^ ME[10]; + out[11] = SE[get_byte(3, B1)] ^ ME[11]; + out[12] = SE[get_byte(0, B3)] ^ ME[12]; + out[13] = SE[get_byte(1, B0)] ^ ME[13]; + out[14] = SE[get_byte(2, B1)] ^ ME[14]; + out[15] = SE[get_byte(3, B2)] ^ ME[15]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* AES Decryption +*/ +void aes_decrypt_n(const byte in[], byte out[], size_t blocks, + const secure_vector& DK, + const secure_vector& MD) + { + BOTAN_ASSERT(DK.size() && MD.size() == 16, "Key was set"); + + const size_t BLOCK_SIZE = 16; + + const u32bit* TD0 = TD; + const u32bit* TD1 = TD + 256; + const u32bit* TD2 = TD + 512; + const u32bit* TD3 = TD + 768; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit T0 = load_be(in, 0) ^ DK[0]; + u32bit T1 = load_be(in, 1) ^ DK[1]; + u32bit T2 = load_be(in, 2) ^ DK[2]; + u32bit T3 = load_be(in, 3) ^ DK[3]; + + u32bit B0 = TD[get_byte(0, T0)] ^ + rotate_right(TD[get_byte(1, T3)], 8) ^ + rotate_right(TD[get_byte(2, T2)], 16) ^ + rotate_right(TD[get_byte(3, T1)], 24) ^ DK[4]; + + u32bit B1 = TD[get_byte(0, T1)] ^ + rotate_right(TD[get_byte(1, T0)], 8) ^ + rotate_right(TD[get_byte(2, T3)], 16) ^ + rotate_right(TD[get_byte(3, T2)], 24) ^ DK[5]; + + u32bit B2 = TD[get_byte(0, T2)] ^ + rotate_right(TD[get_byte(1, T1)], 8) ^ + rotate_right(TD[get_byte(2, T0)], 16) ^ + rotate_right(TD[get_byte(3, T3)], 24) ^ DK[6]; + + u32bit B3 = TD[get_byte(0, T3)] ^ + rotate_right(TD[get_byte(1, T2)], 8) ^ + rotate_right(TD[get_byte(2, T1)], 16) ^ + rotate_right(TD[get_byte(3, T0)], 24) ^ DK[7]; + + for(size_t r = 2*4; r < DK.size(); r += 2*4) + { + T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(1, B3)] ^ + TD2[get_byte(2, B2)] ^ TD3[get_byte(3, B1)] ^ DK[r]; + T1 = TD0[get_byte(0, B1)] ^ TD1[get_byte(1, B0)] ^ + TD2[get_byte(2, B3)] ^ TD3[get_byte(3, B2)] ^ DK[r+1]; + T2 = TD0[get_byte(0, B2)] ^ TD1[get_byte(1, B1)] ^ + TD2[get_byte(2, B0)] ^ TD3[get_byte(3, B3)] ^ DK[r+2]; + T3 = TD0[get_byte(0, B3)] ^ TD1[get_byte(1, B2)] ^ + TD2[get_byte(2, B1)] ^ TD3[get_byte(3, B0)] ^ DK[r+3]; + + B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(1, T3)] ^ + TD2[get_byte(2, T2)] ^ TD3[get_byte(3, T1)] ^ DK[r+4]; + B1 = TD0[get_byte(0, T1)] ^ TD1[get_byte(1, T0)] ^ + TD2[get_byte(2, T3)] ^ TD3[get_byte(3, T2)] ^ DK[r+5]; + B2 = TD0[get_byte(0, T2)] ^ TD1[get_byte(1, T1)] ^ + TD2[get_byte(2, T0)] ^ TD3[get_byte(3, T3)] ^ DK[r+6]; + B3 = TD0[get_byte(0, T3)] ^ TD1[get_byte(1, T2)] ^ + TD2[get_byte(2, T1)] ^ TD3[get_byte(3, T0)] ^ DK[r+7]; + } + + out[ 0] = SD[get_byte(0, B0)] ^ MD[0]; + out[ 1] = SD[get_byte(1, B3)] ^ MD[1]; + out[ 2] = SD[get_byte(2, B2)] ^ MD[2]; + out[ 3] = SD[get_byte(3, B1)] ^ MD[3]; + out[ 4] = SD[get_byte(0, B1)] ^ MD[4]; + out[ 5] = SD[get_byte(1, B0)] ^ MD[5]; + out[ 6] = SD[get_byte(2, B3)] ^ MD[6]; + out[ 7] = SD[get_byte(3, B2)] ^ MD[7]; + out[ 8] = SD[get_byte(0, B2)] ^ MD[8]; + out[ 9] = SD[get_byte(1, B1)] ^ MD[9]; + out[10] = SD[get_byte(2, B0)] ^ MD[10]; + out[11] = SD[get_byte(3, B3)] ^ MD[11]; + out[12] = SD[get_byte(0, B3)] ^ MD[12]; + out[13] = SD[get_byte(1, B2)] ^ MD[13]; + out[14] = SD[get_byte(2, B1)] ^ MD[14]; + out[15] = SD[get_byte(3, B0)] ^ MD[15]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +void aes_key_schedule(const byte key[], size_t length, + secure_vector& EK, + secure_vector& DK, + secure_vector& ME, + secure_vector& MD) + { + static const u32bit RC[10] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; + + const size_t rounds = (length / 4) + 6; + + secure_vector XEK(length + 32), XDK(length + 32); + + const size_t X = length / 4; + for(size_t i = 0; i != X; ++i) + XEK[i] = load_be(key, i); + + for(size_t i = X; i < 4*(rounds+1); i += X) + { + XEK[i] = XEK[i-X] ^ RC[(i-X)/X] ^ + make_u32bit(SE[get_byte(1, XEK[i-1])], + SE[get_byte(2, XEK[i-1])], + SE[get_byte(3, XEK[i-1])], + SE[get_byte(0, XEK[i-1])]); + + for(size_t j = 1; j != X; ++j) + { + XEK[i+j] = XEK[i+j-X]; + + if(X == 8 && j == 4) + XEK[i+j] ^= make_u32bit(SE[get_byte(0, XEK[i+j-1])], + SE[get_byte(1, XEK[i+j-1])], + SE[get_byte(2, XEK[i+j-1])], + SE[get_byte(3, XEK[i+j-1])]); + else + XEK[i+j] ^= XEK[i+j-1]; + } + } + + for(size_t i = 0; i != 4*(rounds+1); i += 4) + { + XDK[i ] = XEK[4*rounds-i ]; + XDK[i+1] = XEK[4*rounds-i+1]; + XDK[i+2] = XEK[4*rounds-i+2]; + XDK[i+3] = XEK[4*rounds-i+3]; + } + + for(size_t i = 4; i != length + 24; ++i) + XDK[i] = TD[SE[get_byte(0, XDK[i])] + 0] ^ + TD[SE[get_byte(1, XDK[i])] + 256] ^ + TD[SE[get_byte(2, XDK[i])] + 512] ^ + TD[SE[get_byte(3, XDK[i])] + 768]; + + ME.resize(16); + MD.resize(16); + + for(size_t i = 0; i != 4; ++i) + { + store_be(XEK[i+4*rounds], &ME[4*i]); + store_be(XEK[i], &MD[4*i]); + } + + EK.resize(length + 24); + DK.resize(length + 24); + copy_mem(&EK[0], &XEK[0], EK.size()); + copy_mem(&DK[0], &XDK[0], DK.size()); + } + +} + +void AES_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_encrypt_n(in, out, blocks, EK, ME); + } + +void AES_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_decrypt_n(in, out, blocks, DK, MD); + } + +void AES_128::key_schedule(const byte key[], size_t length) + { + aes_key_schedule(key, length, EK, DK, ME, MD); + } + +void AES_128::clear() + { + zap(EK); + zap(DK); + zap(ME); + zap(MD); + } + +void AES_192::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_encrypt_n(in, out, blocks, EK, ME); + } + +void AES_192::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_decrypt_n(in, out, blocks, DK, MD); + } + +void AES_192::key_schedule(const byte key[], size_t length) + { + aes_key_schedule(key, length, EK, DK, ME, MD); + } + +void AES_192::clear() + { + zap(EK); + zap(DK); + zap(ME); + zap(MD); + } + +void AES_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_encrypt_n(in, out, blocks, EK, ME); + } + +void AES_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_decrypt_n(in, out, blocks, DK, MD); + } + +void AES_256::key_schedule(const byte key[], size_t length) + { + aes_key_schedule(key, length, EK, DK, ME, MD); + } + +void AES_256::clear() + { + zap(EK); + zap(DK); + zap(ME); + zap(MD); + } + +} diff --git a/src/lib/block/aes/aes.h b/src/lib/block/aes/aes.h new file mode 100644 index 000000000..5ddd39b08 --- /dev/null +++ b/src/lib/block/aes/aes.h @@ -0,0 +1,77 @@ +/* +* AES +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_H__ +#define BOTAN_AES_H__ + +#include + +namespace Botan { + +/** +* AES-128 +*/ +class BOTAN_DLL AES_128 : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const { return "AES-128"; } + BlockCipher* clone() const { return new AES_128; } + private: + void key_schedule(const byte key[], size_t length); + + secure_vector EK, DK; + secure_vector ME, MD; + }; + +/** +* AES-192 +*/ +class BOTAN_DLL AES_192 : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const { return "AES-192"; } + BlockCipher* clone() const { return new AES_192; } + private: + void key_schedule(const byte key[], size_t length); + + secure_vector EK, DK; + secure_vector ME, MD; + }; + +/** +* AES-256 +*/ +class BOTAN_DLL AES_256 : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const { return "AES-256"; } + BlockCipher* clone() const { return new AES_256; } + private: + void key_schedule(const byte key[], size_t length); + + secure_vector EK, DK; + secure_vector ME, MD; + }; + +} + +#endif diff --git a/src/lib/block/aes/info.txt b/src/lib/block/aes/info.txt new file mode 100644 index 000000000..09bd9a0ca --- /dev/null +++ b/src/lib/block/aes/info.txt @@ -0,0 +1 @@ +define AES 20131128 diff --git a/src/lib/block/aes_ni/aes_ni.cpp b/src/lib/block/aes_ni/aes_ni.cpp new file mode 100644 index 000000000..c752d359c --- /dev/null +++ b/src/lib/block/aes_ni/aes_ni.cpp @@ -0,0 +1,795 @@ +/* +* AES using AES-NI instructions +* (C) 2009,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +__m128i aes_128_key_expansion(__m128i key, __m128i key_with_rcon) + { + key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(3,3,3,3)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + return _mm_xor_si128(key, key_with_rcon); + } + +void aes_192_key_expansion(__m128i* K1, __m128i* K2, __m128i key2_with_rcon, + u32bit out[], bool last) + { + __m128i key1 = *K1; + __m128i key2 = *K2; + + key2_with_rcon = _mm_shuffle_epi32(key2_with_rcon, _MM_SHUFFLE(1,1,1,1)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, key2_with_rcon); + + *K1 = key1; + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), key1); + + if(last) + return; + + key2 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4)); + key2 = _mm_xor_si128(key2, _mm_shuffle_epi32(key1, _MM_SHUFFLE(3,3,3,3))); + + *K2 = key2; + out[4] = _mm_cvtsi128_si32(key2); + out[5] = _mm_cvtsi128_si32(_mm_srli_si128(key2, 4)); + } + +/* +* The second half of the AES-256 key expansion (other half same as AES-128) +*/ +__m128i aes_256_key_expansion(__m128i key, __m128i key2) + { + __m128i key_with_rcon = _mm_aeskeygenassist_si128(key2, 0x00); + key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(2,2,2,2)); + + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + return _mm_xor_si128(key, key_with_rcon); + } + +} + +#define AES_ENC_4_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesenc_si128(B0, K); \ + B1 = _mm_aesenc_si128(B1, K); \ + B2 = _mm_aesenc_si128(B2, K); \ + B3 = _mm_aesenc_si128(B3, K); \ + } while(0) + +#define AES_ENC_4_LAST_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesenclast_si128(B0, K); \ + B1 = _mm_aesenclast_si128(B1, K); \ + B2 = _mm_aesenclast_si128(B2, K); \ + B3 = _mm_aesenclast_si128(B3, K); \ + } while(0) + +#define AES_DEC_4_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesdec_si128(B0, K); \ + B1 = _mm_aesdec_si128(B1, K); \ + B2 = _mm_aesdec_si128(B2, K); \ + B3 = _mm_aesdec_si128(B3, K); \ + } while(0) + +#define AES_DEC_4_LAST_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesdeclast_si128(B0, K); \ + B1 = _mm_aesdeclast_si128(B1, K); \ + B2 = _mm_aesdeclast_si128(B2, K); \ + B3 = _mm_aesdeclast_si128(B3, K); \ + } while(0) + +/* +* AES-128 Encryption +*/ +void AES_128_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(&EK[0]); + + __m128i K0 = _mm_loadu_si128(key_mm); + __m128i K1 = _mm_loadu_si128(key_mm + 1); + __m128i K2 = _mm_loadu_si128(key_mm + 2); + __m128i K3 = _mm_loadu_si128(key_mm + 3); + __m128i K4 = _mm_loadu_si128(key_mm + 4); + __m128i K5 = _mm_loadu_si128(key_mm + 5); + __m128i K6 = _mm_loadu_si128(key_mm + 6); + __m128i K7 = _mm_loadu_si128(key_mm + 7); + __m128i K8 = _mm_loadu_si128(key_mm + 8); + __m128i K9 = _mm_loadu_si128(key_mm + 9); + __m128i K10 = _mm_loadu_si128(key_mm + 10); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_LAST_ROUNDS(K10); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenclast_si128(B, K10); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-128 Decryption +*/ +void AES_128_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(&DK[0]); + + __m128i K0 = _mm_loadu_si128(key_mm); + __m128i K1 = _mm_loadu_si128(key_mm + 1); + __m128i K2 = _mm_loadu_si128(key_mm + 2); + __m128i K3 = _mm_loadu_si128(key_mm + 3); + __m128i K4 = _mm_loadu_si128(key_mm + 4); + __m128i K5 = _mm_loadu_si128(key_mm + 5); + __m128i K6 = _mm_loadu_si128(key_mm + 6); + __m128i K7 = _mm_loadu_si128(key_mm + 7); + __m128i K8 = _mm_loadu_si128(key_mm + 8); + __m128i K9 = _mm_loadu_si128(key_mm + 9); + __m128i K10 = _mm_loadu_si128(key_mm + 10); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_LAST_ROUNDS(K10); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdeclast_si128(B, K10); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-128 Key Schedule +*/ +void AES_128_NI::key_schedule(const byte key[], size_t) + { + EK.resize(44); + DK.resize(44); + + #define AES_128_key_exp(K, RCON) \ + aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON)) + + __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); + __m128i K1 = AES_128_key_exp(K0, 0x01); + __m128i K2 = AES_128_key_exp(K1, 0x02); + __m128i K3 = AES_128_key_exp(K2, 0x04); + __m128i K4 = AES_128_key_exp(K3, 0x08); + __m128i K5 = AES_128_key_exp(K4, 0x10); + __m128i K6 = AES_128_key_exp(K5, 0x20); + __m128i K7 = AES_128_key_exp(K6, 0x40); + __m128i K8 = AES_128_key_exp(K7, 0x80); + __m128i K9 = AES_128_key_exp(K8, 0x1B); + __m128i K10 = AES_128_key_exp(K9, 0x36); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + _mm_storeu_si128(EK_mm , K0); + _mm_storeu_si128(EK_mm + 1, K1); + _mm_storeu_si128(EK_mm + 2, K2); + _mm_storeu_si128(EK_mm + 3, K3); + _mm_storeu_si128(EK_mm + 4, K4); + _mm_storeu_si128(EK_mm + 5, K5); + _mm_storeu_si128(EK_mm + 6, K6); + _mm_storeu_si128(EK_mm + 7, K7); + _mm_storeu_si128(EK_mm + 8, K8); + _mm_storeu_si128(EK_mm + 9, K9); + _mm_storeu_si128(EK_mm + 10, K10); + + // Now generate decryption keys + + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); + _mm_storeu_si128(DK_mm , K10); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K9)); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K8)); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K7)); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K6)); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K5)); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K4)); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K3)); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K2)); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K1)); + _mm_storeu_si128(DK_mm + 10, K0); + } + +/* +* Clear memory of sensitive data +*/ +void AES_128_NI::clear() + { + zap(EK); + zap(DK); + } + +/* +* AES-192 Encryption +*/ +void AES_192_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(&EK[0]); + + __m128i K0 = _mm_loadu_si128(key_mm); + __m128i K1 = _mm_loadu_si128(key_mm + 1); + __m128i K2 = _mm_loadu_si128(key_mm + 2); + __m128i K3 = _mm_loadu_si128(key_mm + 3); + __m128i K4 = _mm_loadu_si128(key_mm + 4); + __m128i K5 = _mm_loadu_si128(key_mm + 5); + __m128i K6 = _mm_loadu_si128(key_mm + 6); + __m128i K7 = _mm_loadu_si128(key_mm + 7); + __m128i K8 = _mm_loadu_si128(key_mm + 8); + __m128i K9 = _mm_loadu_si128(key_mm + 9); + __m128i K10 = _mm_loadu_si128(key_mm + 10); + __m128i K11 = _mm_loadu_si128(key_mm + 11); + __m128i K12 = _mm_loadu_si128(key_mm + 12); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_LAST_ROUNDS(K12); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenc_si128(B, K10); + B = _mm_aesenc_si128(B, K11); + B = _mm_aesenclast_si128(B, K12); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-192 Decryption +*/ +void AES_192_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(&DK[0]); + + __m128i K0 = _mm_loadu_si128(key_mm); + __m128i K1 = _mm_loadu_si128(key_mm + 1); + __m128i K2 = _mm_loadu_si128(key_mm + 2); + __m128i K3 = _mm_loadu_si128(key_mm + 3); + __m128i K4 = _mm_loadu_si128(key_mm + 4); + __m128i K5 = _mm_loadu_si128(key_mm + 5); + __m128i K6 = _mm_loadu_si128(key_mm + 6); + __m128i K7 = _mm_loadu_si128(key_mm + 7); + __m128i K8 = _mm_loadu_si128(key_mm + 8); + __m128i K9 = _mm_loadu_si128(key_mm + 9); + __m128i K10 = _mm_loadu_si128(key_mm + 10); + __m128i K11 = _mm_loadu_si128(key_mm + 11); + __m128i K12 = _mm_loadu_si128(key_mm + 12); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_LAST_ROUNDS(K12); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdec_si128(B, K10); + B = _mm_aesdec_si128(B, K11); + B = _mm_aesdeclast_si128(B, K12); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-192 Key Schedule +*/ +void AES_192_NI::key_schedule(const byte key[], size_t) + { + EK.resize(52); + DK.resize(52); + + __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); + __m128i K1 = _mm_loadu_si128(reinterpret_cast(key + 8)); + K1 = _mm_srli_si128(K1, 8); + + load_le(&EK[0], key, 6); + + #define AES_192_key_exp(RCON, EK_OFF) \ + aes_192_key_expansion(&K0, &K1, \ + _mm_aeskeygenassist_si128(K1, RCON), \ + &EK[EK_OFF], EK_OFF == 48) + + AES_192_key_exp(0x01, 6); + AES_192_key_exp(0x02, 12); + AES_192_key_exp(0x04, 18); + AES_192_key_exp(0x08, 24); + AES_192_key_exp(0x10, 30); + AES_192_key_exp(0x20, 36); + AES_192_key_exp(0x40, 42); + AES_192_key_exp(0x80, 48); + + #undef AES_192_key_exp + + // Now generate decryption keys + const __m128i* EK_mm = reinterpret_cast(&EK[0]); + + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); + _mm_storeu_si128(DK_mm , _mm_loadu_si128(EK_mm + 12)); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 11))); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 10))); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 9))); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 8))); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 7))); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 6))); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 5))); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 4))); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 3))); + _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 2))); + _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 1))); + _mm_storeu_si128(DK_mm + 12, _mm_loadu_si128(EK_mm + 0)); + } + +/* +* Clear memory of sensitive data +*/ +void AES_192_NI::clear() + { + zap(EK); + zap(DK); + } + +/* +* AES-256 Encryption +*/ +void AES_256_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(&EK[0]); + + __m128i K0 = _mm_loadu_si128(key_mm); + __m128i K1 = _mm_loadu_si128(key_mm + 1); + __m128i K2 = _mm_loadu_si128(key_mm + 2); + __m128i K3 = _mm_loadu_si128(key_mm + 3); + __m128i K4 = _mm_loadu_si128(key_mm + 4); + __m128i K5 = _mm_loadu_si128(key_mm + 5); + __m128i K6 = _mm_loadu_si128(key_mm + 6); + __m128i K7 = _mm_loadu_si128(key_mm + 7); + __m128i K8 = _mm_loadu_si128(key_mm + 8); + __m128i K9 = _mm_loadu_si128(key_mm + 9); + __m128i K10 = _mm_loadu_si128(key_mm + 10); + __m128i K11 = _mm_loadu_si128(key_mm + 11); + __m128i K12 = _mm_loadu_si128(key_mm + 12); + __m128i K13 = _mm_loadu_si128(key_mm + 13); + __m128i K14 = _mm_loadu_si128(key_mm + 14); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_ROUNDS(K12); + AES_ENC_4_ROUNDS(K13); + AES_ENC_4_LAST_ROUNDS(K14); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenc_si128(B, K10); + B = _mm_aesenc_si128(B, K11); + B = _mm_aesenc_si128(B, K12); + B = _mm_aesenc_si128(B, K13); + B = _mm_aesenclast_si128(B, K14); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-256 Decryption +*/ +void AES_256_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(&DK[0]); + + __m128i K0 = _mm_loadu_si128(key_mm); + __m128i K1 = _mm_loadu_si128(key_mm + 1); + __m128i K2 = _mm_loadu_si128(key_mm + 2); + __m128i K3 = _mm_loadu_si128(key_mm + 3); + __m128i K4 = _mm_loadu_si128(key_mm + 4); + __m128i K5 = _mm_loadu_si128(key_mm + 5); + __m128i K6 = _mm_loadu_si128(key_mm + 6); + __m128i K7 = _mm_loadu_si128(key_mm + 7); + __m128i K8 = _mm_loadu_si128(key_mm + 8); + __m128i K9 = _mm_loadu_si128(key_mm + 9); + __m128i K10 = _mm_loadu_si128(key_mm + 10); + __m128i K11 = _mm_loadu_si128(key_mm + 11); + __m128i K12 = _mm_loadu_si128(key_mm + 12); + __m128i K13 = _mm_loadu_si128(key_mm + 13); + __m128i K14 = _mm_loadu_si128(key_mm + 14); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_ROUNDS(K12); + AES_DEC_4_ROUNDS(K13); + AES_DEC_4_LAST_ROUNDS(K14); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdec_si128(B, K10); + B = _mm_aesdec_si128(B, K11); + B = _mm_aesdec_si128(B, K12); + B = _mm_aesdec_si128(B, K13); + B = _mm_aesdeclast_si128(B, K14); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-256 Key Schedule +*/ +void AES_256_NI::key_schedule(const byte key[], size_t) + { + EK.resize(60); + DK.resize(60); + + __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); + __m128i K1 = _mm_loadu_si128(reinterpret_cast(key + 16)); + + __m128i K2 = aes_128_key_expansion(K0, _mm_aeskeygenassist_si128(K1, 0x01)); + __m128i K3 = aes_256_key_expansion(K1, K2); + + __m128i K4 = aes_128_key_expansion(K2, _mm_aeskeygenassist_si128(K3, 0x02)); + __m128i K5 = aes_256_key_expansion(K3, K4); + + __m128i K6 = aes_128_key_expansion(K4, _mm_aeskeygenassist_si128(K5, 0x04)); + __m128i K7 = aes_256_key_expansion(K5, K6); + + __m128i K8 = aes_128_key_expansion(K6, _mm_aeskeygenassist_si128(K7, 0x08)); + __m128i K9 = aes_256_key_expansion(K7, K8); + + __m128i K10 = aes_128_key_expansion(K8, _mm_aeskeygenassist_si128(K9, 0x10)); + __m128i K11 = aes_256_key_expansion(K9, K10); + + __m128i K12 = aes_128_key_expansion(K10, _mm_aeskeygenassist_si128(K11, 0x20)); + __m128i K13 = aes_256_key_expansion(K11, K12); + + __m128i K14 = aes_128_key_expansion(K12, _mm_aeskeygenassist_si128(K13, 0x40)); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + _mm_storeu_si128(EK_mm , K0); + _mm_storeu_si128(EK_mm + 1, K1); + _mm_storeu_si128(EK_mm + 2, K2); + _mm_storeu_si128(EK_mm + 3, K3); + _mm_storeu_si128(EK_mm + 4, K4); + _mm_storeu_si128(EK_mm + 5, K5); + _mm_storeu_si128(EK_mm + 6, K6); + _mm_storeu_si128(EK_mm + 7, K7); + _mm_storeu_si128(EK_mm + 8, K8); + _mm_storeu_si128(EK_mm + 9, K9); + _mm_storeu_si128(EK_mm + 10, K10); + _mm_storeu_si128(EK_mm + 11, K11); + _mm_storeu_si128(EK_mm + 12, K12); + _mm_storeu_si128(EK_mm + 13, K13); + _mm_storeu_si128(EK_mm + 14, K14); + + // Now generate decryption keys + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); + _mm_storeu_si128(DK_mm , K14); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K13)); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K12)); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K11)); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K10)); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K9)); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K8)); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K7)); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K6)); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K5)); + _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(K4)); + _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(K3)); + _mm_storeu_si128(DK_mm + 12, _mm_aesimc_si128(K2)); + _mm_storeu_si128(DK_mm + 13, _mm_aesimc_si128(K1)); + _mm_storeu_si128(DK_mm + 14, K0); + } + +/* +* Clear memory of sensitive data +*/ +void AES_256_NI::clear() + { + zap(EK); + zap(DK); + } + +#undef AES_ENC_4_ROUNDS +#undef AES_ENC_4_LAST_ROUNDS +#undef AES_DEC_4_ROUNDS +#undef AES_DEC_4_LAST_ROUNDS + +} diff --git a/src/lib/block/aes_ni/aes_ni.h b/src/lib/block/aes_ni/aes_ni.h new file mode 100644 index 000000000..aac6b0808 --- /dev/null +++ b/src/lib/block/aes_ni/aes_ni.h @@ -0,0 +1,77 @@ +/* +* AES using AES-NI instructions +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_NI_H__ +#define BOTAN_AES_NI_H__ + +#include + +namespace Botan { + +/** +* AES-128 using AES-NI +*/ +class BOTAN_DLL AES_128_NI : public Block_Cipher_Fixed_Params<16, 16> + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "AES-128"; } + BlockCipher* clone() const { return new AES_128_NI; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +/** +* AES-192 using AES-NI +*/ +class BOTAN_DLL AES_192_NI : public Block_Cipher_Fixed_Params<16, 24> + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "AES-192"; } + BlockCipher* clone() const { return new AES_192_NI; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +/** +* AES-256 using AES-NI +*/ +class BOTAN_DLL AES_256_NI : public Block_Cipher_Fixed_Params<16, 32> + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "AES-256"; } + BlockCipher* clone() const { return new AES_256_NI; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +} + +#endif diff --git a/src/lib/block/aes_ni/info.txt b/src/lib/block/aes_ni/info.txt new file mode 100644 index 000000000..270b00d9d --- /dev/null +++ b/src/lib/block/aes_ni/info.txt @@ -0,0 +1,9 @@ +define AES_NI 20131128 + +load_on auto + +need_isa aesni + + +aes_isa_eng + diff --git a/src/lib/block/aes_ssse3/aes_ssse3.cpp b/src/lib/block/aes_ssse3/aes_ssse3.cpp new file mode 100644 index 000000000..476b004bb --- /dev/null +++ b/src/lib/block/aes_ssse3/aes_ssse3.cpp @@ -0,0 +1,608 @@ +/* +* AES using SSSE3 +* (C) 2010 Jack Lloyd +* +* This is more or less a direct translation of public domain x86-64 +* assembly written by Mike Hamburg, described in "Accelerating AES +* with Vector Permute Instructions" (CHES 2009). His original code is +* available at http://crypto.stanford.edu/vpaes/ +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +const __m128i low_nibs = _mm_set1_epi8(0x0F); + +const __m128i k_ipt1 = _mm_set_epi32( + 0xCABAE090, 0x52227808, 0xC2B2E898, 0x5A2A7000); +const __m128i k_ipt2 = _mm_set_epi32( + 0xCD80B1FC, 0xB0FDCC81, 0x4C01307D, 0x317C4D00); + +const __m128i k_inv1 = _mm_set_epi32( + 0x04070309, 0x0A0B0C02, 0x0E05060F, 0x0D080180); +const __m128i k_inv2 = _mm_set_epi32( + 0x030D0E0C, 0x02050809, 0x01040A06, 0x0F0B0780); + +const __m128i sb1u = _mm_set_epi32( + 0xA5DF7A6E, 0x142AF544, 0xB19BE18F, 0xCB503E00); +const __m128i sb1t = _mm_set_epi32( + 0x3BF7CCC1, 0x0D2ED9EF, 0x3618D415, 0xFAE22300); + +const __m128i mc_forward[4] = { + _mm_set_epi32(0x0C0F0E0D, 0x080B0A09, 0x04070605, 0x00030201), + _mm_set_epi32(0x00030201, 0x0C0F0E0D, 0x080B0A09, 0x04070605), + _mm_set_epi32(0x04070605, 0x00030201, 0x0C0F0E0D, 0x080B0A09), + _mm_set_epi32(0x080B0A09, 0x04070605, 0x00030201, 0x0C0F0E0D) +}; + +const __m128i sr[4] = { + _mm_set_epi32(0x0F0E0D0C, 0x0B0A0908, 0x07060504, 0x03020100), + _mm_set_epi32(0x0B06010C, 0x07020D08, 0x030E0904, 0x0F0A0500), + _mm_set_epi32(0x070E050C, 0x030A0108, 0x0F060D04, 0x0B020900), + _mm_set_epi32(0x0306090C, 0x0F020508, 0x0B0E0104, 0x070A0D00), +}; + +#define mm_xor3(x, y, z) _mm_xor_si128(x, _mm_xor_si128(y, z)) + +__m128i aes_schedule_transform(__m128i input, + __m128i table_1, + __m128i table_2) + { + __m128i i_1 = _mm_and_si128(low_nibs, input); + __m128i i_2 = _mm_srli_epi32(_mm_andnot_si128(low_nibs, input), 4); + + input = _mm_and_si128(low_nibs, input); + + return _mm_xor_si128( + _mm_shuffle_epi8(table_1, i_1), + _mm_shuffle_epi8(table_2, i_2)); + } + +__m128i aes_schedule_mangle(__m128i k, byte round_no) + { + __m128i t = _mm_shuffle_epi8(_mm_xor_si128(k, _mm_set1_epi8(0x5B)), + mc_forward[0]); + + __m128i t2 = t; + + t = _mm_shuffle_epi8(t, mc_forward[0]); + + t2 = mm_xor3(t2, t, _mm_shuffle_epi8(t, mc_forward[0])); + + return _mm_shuffle_epi8(t2, sr[round_no % 4]); + } + +__m128i aes_schedule_192_smear(__m128i x, __m128i y) + { + return mm_xor3(y, + _mm_shuffle_epi32(x, 0xFE), + _mm_shuffle_epi32(y, 0x80)); + } + +__m128i aes_schedule_mangle_dec(__m128i k, byte round_no) + { + const __m128i dsk[8] = { + _mm_set_epi32(0x4AED9334, 0x82255BFC, 0xB6116FC8, 0x7ED9A700), + _mm_set_epi32(0x8BB89FAC, 0xE9DAFDCE, 0x45765162, 0x27143300), + _mm_set_epi32(0x4622EE8A, 0xADC90561, 0x27438FEB, 0xCCA86400), + _mm_set_epi32(0x73AEE13C, 0xBD602FF2, 0x815C13CE, 0x4F92DD00), + _mm_set_epi32(0xF83F3EF9, 0xFA3D3CFB, 0x03C4C502, 0x01C6C700), + _mm_set_epi32(0xA5526A9D, 0x7384BC4B, 0xEE1921D6, 0x38CFF700), + _mm_set_epi32(0xA080D3F3, 0x10306343, 0xE3C390B0, 0x53732000), + _mm_set_epi32(0x2F45AEC4, 0x8CE60D67, 0xA0CA214B, 0x036982E8) + }; + + __m128i t = aes_schedule_transform(k, dsk[0], dsk[1]); + __m128i output = _mm_shuffle_epi8(t, mc_forward[0]); + + t = aes_schedule_transform(t, dsk[2], dsk[3]); + output = _mm_shuffle_epi8(_mm_xor_si128(t, output), mc_forward[0]); + + t = aes_schedule_transform(t, dsk[4], dsk[5]); + output = _mm_shuffle_epi8(_mm_xor_si128(t, output), mc_forward[0]); + + t = aes_schedule_transform(t, dsk[6], dsk[7]); + output = _mm_shuffle_epi8(_mm_xor_si128(t, output), mc_forward[0]); + + return _mm_shuffle_epi8(output, sr[round_no % 4]); + } + +__m128i aes_schedule_mangle_last(__m128i k, byte round_no) + { + const __m128i out_tr1 = _mm_set_epi32( + 0xF7974121, 0xDEBE6808, 0xFF9F4929, 0xD6B66000); + const __m128i out_tr2 = _mm_set_epi32( + 0xE10D5DB1, 0xB05C0CE0, 0x01EDBD51, 0x50BCEC00); + + k = _mm_shuffle_epi8(k, sr[round_no % 4]); + k = _mm_xor_si128(k, _mm_set1_epi8(0x5B)); + return aes_schedule_transform(k, out_tr1, out_tr2); + } + +__m128i aes_schedule_mangle_last_dec(__m128i k) + { + const __m128i deskew1 = _mm_set_epi32( + 0x1DFEB95A, 0x5DBEF91A, 0x07E4A340, 0x47A4E300); + const __m128i deskew2 = _mm_set_epi32( + 0x2841C2AB, 0xF49D1E77, 0x5F36B5DC, 0x83EA6900); + + k = _mm_xor_si128(k, _mm_set1_epi8(0x5B)); + return aes_schedule_transform(k, deskew1, deskew2); + } + +__m128i aes_schedule_round(__m128i* rcon, __m128i input1, __m128i input2) + { + if(rcon) + { + input2 = _mm_xor_si128(_mm_alignr_epi8(_mm_setzero_si128(), *rcon, 15), + input2); + + *rcon = _mm_alignr_epi8(*rcon, *rcon, 15); // next rcon + + input1 = _mm_shuffle_epi32(input1, 0xFF); // rotate + input1 = _mm_alignr_epi8(input1, input1, 1); + } + + __m128i smeared = _mm_xor_si128(input2, _mm_slli_si128(input2, 4)); + smeared = mm_xor3(smeared, _mm_slli_si128(smeared, 8), _mm_set1_epi8(0x5B)); + + __m128i t = _mm_srli_epi32(_mm_andnot_si128(low_nibs, input1), 4); + + input1 = _mm_and_si128(low_nibs, input1); + + __m128i t2 = _mm_shuffle_epi8(k_inv2, input1); + + input1 = _mm_xor_si128(input1, t); + + __m128i t3 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, t)); + __m128i t4 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, input1)); + + __m128i t5 = _mm_xor_si128(input1, _mm_shuffle_epi8(k_inv1, t3)); + __m128i t6 = _mm_xor_si128(t, _mm_shuffle_epi8(k_inv1, t4)); + + return mm_xor3(_mm_shuffle_epi8(sb1u, t5), + _mm_shuffle_epi8(sb1t, t6), + smeared); + } + +__m128i aes_ssse3_encrypt(__m128i B, const __m128i* keys, size_t rounds) + { + const __m128i sb2u = _mm_set_epi32( + 0x5EB7E955, 0xBC982FCD, 0xE27A93C6, 0x0B712400); + const __m128i sb2t = _mm_set_epi32( + 0xC2A163C8, 0xAB82234A, 0x69EB8840, 0x0AE12900); + + const __m128i sbou = _mm_set_epi32( + 0x15AABF7A, 0xC502A878, 0xD0D26D17, 0x6FBDC700); + const __m128i sbot = _mm_set_epi32( + 0x8E1E90D1, 0x412B35FA, 0xCFE474A5, 0x5FBB6A00); + + const __m128i mc_backward[4] = { + _mm_set_epi32(0x0E0D0C0F, 0x0A09080B, 0x06050407, 0x02010003), + _mm_set_epi32(0x0A09080B, 0x06050407, 0x02010003, 0x0E0D0C0F), + _mm_set_epi32(0x06050407, 0x02010003, 0x0E0D0C0F, 0x0A09080B), + _mm_set_epi32(0x02010003, 0x0E0D0C0F, 0x0A09080B, 0x06050407), + }; + + B = mm_xor3(_mm_shuffle_epi8(k_ipt1, _mm_and_si128(low_nibs, B)), + _mm_shuffle_epi8(k_ipt2, + _mm_srli_epi32( + _mm_andnot_si128(low_nibs, B), + 4)), + _mm_loadu_si128(keys)); + + for(size_t r = 1; ; ++r) + { + const __m128i K = _mm_loadu_si128(keys + r); + + __m128i t = _mm_srli_epi32(_mm_andnot_si128(low_nibs, B), 4); + + B = _mm_and_si128(low_nibs, B); + + __m128i t2 = _mm_shuffle_epi8(k_inv2, B); + + B = _mm_xor_si128(B, t); + + __m128i t3 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, t)); + __m128i t4 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, B)); + + __m128i t5 = _mm_xor_si128(B, _mm_shuffle_epi8(k_inv1, t3)); + __m128i t6 = _mm_xor_si128(t, _mm_shuffle_epi8(k_inv1, t4)); + + if(r == rounds) + { + B = _mm_shuffle_epi8( + mm_xor3(_mm_shuffle_epi8(sbou, t5), + _mm_shuffle_epi8(sbot, t6), + K), + sr[r % 4]); + + return B; + } + + __m128i t7 = mm_xor3(_mm_shuffle_epi8(sb1t, t6), + _mm_shuffle_epi8(sb1u, t5), + K); + + __m128i t8 = mm_xor3(_mm_shuffle_epi8(sb2t, t6), + _mm_shuffle_epi8(sb2u, t5), + _mm_shuffle_epi8(t7, mc_forward[r % 4])); + + B = mm_xor3(_mm_shuffle_epi8(t8, mc_forward[r % 4]), + _mm_shuffle_epi8(t7, mc_backward[r % 4]), + t8); + } + } + +__m128i aes_ssse3_decrypt(__m128i B, const __m128i* keys, size_t rounds) + { + const __m128i k_dipt1 = _mm_set_epi32( + 0x154A411E, 0x114E451A, 0x0F505B04, 0x0B545F00); + const __m128i k_dipt2 = _mm_set_epi32( + 0x12771772, 0xF491F194, 0x86E383E6, 0x60056500); + + const __m128i sb9u = _mm_set_epi32( + 0xCAD51F50, 0x4F994CC9, 0x851C0353, 0x9A86D600); + const __m128i sb9t = _mm_set_epi32( + 0x725E2C9E, 0xB2FBA565, 0xC03B1789, 0xECD74900); + + const __m128i sbeu = _mm_set_epi32( + 0x22426004, 0x64B4F6B0, 0x46F29296, 0x26D4D000); + const __m128i sbet = _mm_set_epi32( + 0x9467F36B, 0x98593E32, 0x0C55A6CD, 0xFFAAC100); + + const __m128i sbdu = _mm_set_epi32( + 0xF56E9B13, 0x882A4439, 0x7D57CCDF, 0xE6B1A200); + const __m128i sbdt = _mm_set_epi32( + 0x2931180D, 0x15DEEFD3, 0x3CE2FAF7, 0x24C6CB00); + + const __m128i sbbu = _mm_set_epi32( + 0x602646F6, 0xB0F2D404, 0xD0226492, 0x96B44200); + const __m128i sbbt = _mm_set_epi32( + 0xF3FF0C3E, 0x3255AA6B, 0xC19498A6, 0xCD596700); + + __m128i mc = mc_forward[3]; + + __m128i t = + _mm_shuffle_epi8(k_dipt2, + _mm_srli_epi32( + _mm_andnot_si128(low_nibs, B), + 4)); + + B = mm_xor3(t, _mm_loadu_si128(keys), + _mm_shuffle_epi8(k_dipt1, _mm_and_si128(B, low_nibs))); + + for(size_t r = 1; ; ++r) + { + const __m128i K = _mm_loadu_si128(keys + r); + + t = _mm_srli_epi32(_mm_andnot_si128(low_nibs, B), 4); + + B = _mm_and_si128(low_nibs, B); + + __m128i t2 = _mm_shuffle_epi8(k_inv2, B); + + B = _mm_xor_si128(B, t); + + __m128i t3 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, t)); + __m128i t4 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, B)); + __m128i t5 = _mm_xor_si128(B, _mm_shuffle_epi8(k_inv1, t3)); + __m128i t6 = _mm_xor_si128(t, _mm_shuffle_epi8(k_inv1, t4)); + + if(r == rounds) + { + const __m128i sbou = _mm_set_epi32( + 0xC7AA6DB9, 0xD4943E2D, 0x1387EA53, 0x7EF94000); + const __m128i sbot = _mm_set_epi32( + 0xCA4B8159, 0xD8C58E9C, 0x12D7560F, 0x93441D00); + + __m128i x = _mm_shuffle_epi8(sbou, t5); + __m128i y = _mm_shuffle_epi8(sbot, t6); + x = _mm_xor_si128(x, K); + x = _mm_xor_si128(x, y); + + const u32bit which_sr = ((((rounds - 1) << 4) ^ 48) & 48) / 16; + return _mm_shuffle_epi8(x, sr[which_sr]); + } + + __m128i t8 = _mm_xor_si128(_mm_shuffle_epi8(sb9t, t6), + _mm_xor_si128(_mm_shuffle_epi8(sb9u, t5), K)); + + __m128i t9 = mm_xor3(_mm_shuffle_epi8(t8, mc), + _mm_shuffle_epi8(sbdu, t5), + _mm_shuffle_epi8(sbdt, t6)); + + __m128i t12 = _mm_xor_si128( + _mm_xor_si128( + _mm_shuffle_epi8(t9, mc), + _mm_shuffle_epi8(sbbu, t5)), + _mm_shuffle_epi8(sbbt, t6)); + + B = _mm_xor_si128(_mm_xor_si128(_mm_shuffle_epi8(t12, mc), + _mm_shuffle_epi8(sbeu, t5)), + _mm_shuffle_epi8(sbet, t6)); + + mc = _mm_alignr_epi8(mc, mc, 12); + } + } + +} + +/* +* AES-128 Encryption +*/ +void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast(&EK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 10)); + } + } + +/* +* AES-128 Decryption +*/ +void AES_128_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast(&DK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 10)); + } + } + +/* +* AES-128 Key Schedule +*/ +void AES_128_SSSE3::key_schedule(const byte keyb[], size_t) + { + __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, + 0x1F8391B9, 0xAF9DEEB6); + + __m128i key = _mm_loadu_si128(reinterpret_cast(keyb)); + + EK.resize(11*4); + DK.resize(11*4); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); + + _mm_storeu_si128(DK_mm + 10, _mm_shuffle_epi8(key, sr[2])); + + key = aes_schedule_transform(key, k_ipt1, k_ipt2); + + _mm_storeu_si128(EK_mm, key); + + for(size_t i = 1; i != 10; ++i) + { + key = aes_schedule_round(&rcon, key, key); + + _mm_storeu_si128(EK_mm + i, + aes_schedule_mangle(key, (12-i) % 4)); + + _mm_storeu_si128(DK_mm + (10-i), + aes_schedule_mangle_dec(key, (10-i) % 4)); + } + + key = aes_schedule_round(&rcon, key, key); + _mm_storeu_si128(EK_mm + 10, aes_schedule_mangle_last(key, 2)); + _mm_storeu_si128(DK_mm, aes_schedule_mangle_last_dec(key)); + } + +void AES_128_SSSE3::clear() + { + zap(EK); + zap(DK); + } + +/* +* AES-192 Encryption +*/ +void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast(&EK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 12)); + } + } + +/* +* AES-192 Decryption +*/ +void AES_192_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast(&DK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 12)); + } + } + +/* +* AES-192 Key Schedule +*/ +void AES_192_SSSE3::key_schedule(const byte keyb[], size_t) + { + __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, + 0x1F8391B9, 0xAF9DEEB6); + + EK.resize(13*4); + DK.resize(13*4); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); + + __m128i key1 = _mm_loadu_si128(reinterpret_cast(keyb)); + __m128i key2 = _mm_loadu_si128(reinterpret_cast((keyb + 8))); + + _mm_storeu_si128(DK_mm + 12, _mm_shuffle_epi8(key1, sr[0])); + + key1 = aes_schedule_transform(key1, k_ipt1, k_ipt2); + key2 = aes_schedule_transform(key2, k_ipt1, k_ipt2); + + _mm_storeu_si128(EK_mm + 0, key1); + + // key2 with 8 high bytes masked off + __m128i t = _mm_slli_si128(_mm_srli_si128(key2, 8), 8); + + for(size_t i = 0; i != 4; ++i) + { + key2 = aes_schedule_round(&rcon, key2, key1); + + _mm_storeu_si128(EK_mm + 3*i+1, + aes_schedule_mangle(_mm_alignr_epi8(key2, t, 8), (i+3)%4)); + _mm_storeu_si128(DK_mm + 11-3*i, + aes_schedule_mangle_dec(_mm_alignr_epi8(key2, t, 8), (i+3)%4)); + + t = aes_schedule_192_smear(key2, t); + + _mm_storeu_si128(EK_mm + 3*i+2, + aes_schedule_mangle(t, (i+2)%4)); + _mm_storeu_si128(DK_mm + 10-3*i, + aes_schedule_mangle_dec(t, (i+2)%4)); + + key2 = aes_schedule_round(&rcon, t, key2); + + if(i == 3) + { + _mm_storeu_si128(EK_mm + 3*i+3, + aes_schedule_mangle_last(key2, (i+1)%4)); + _mm_storeu_si128(DK_mm + 9-3*i, + aes_schedule_mangle_last_dec(key2)); + } + else + { + _mm_storeu_si128(EK_mm + 3*i+3, + aes_schedule_mangle(key2, (i+1)%4)); + _mm_storeu_si128(DK_mm + 9-3*i, + aes_schedule_mangle_dec(key2, (i+1)%4)); + } + + key1 = key2; + key2 = aes_schedule_192_smear(key2, + _mm_slli_si128(_mm_srli_si128(t, 8), 8)); + t = _mm_slli_si128(_mm_srli_si128(key2, 8), 8); + } + } + +void AES_192_SSSE3::clear() + { + zap(EK); + zap(DK); + } + +/* +* AES-256 Encryption +*/ +void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast(&EK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 14)); + } + } + +/* +* AES-256 Decryption +*/ +void AES_256_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast(&DK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 14)); + } + } + +/* +* AES-256 Key Schedule +*/ +void AES_256_SSSE3::key_schedule(const byte keyb[], size_t) + { + __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, + 0x1F8391B9, 0xAF9DEEB6); + + EK.resize(15*4); + DK.resize(15*4); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); + + __m128i key1 = _mm_loadu_si128(reinterpret_cast(keyb)); + __m128i key2 = _mm_loadu_si128(reinterpret_cast((keyb + 16))); + + _mm_storeu_si128(DK_mm + 14, _mm_shuffle_epi8(key1, sr[2])); + + key1 = aes_schedule_transform(key1, k_ipt1, k_ipt2); + key2 = aes_schedule_transform(key2, k_ipt1, k_ipt2); + + _mm_storeu_si128(EK_mm + 0, key1); + _mm_storeu_si128(EK_mm + 1, aes_schedule_mangle(key2, 3)); + + _mm_storeu_si128(DK_mm + 13, aes_schedule_mangle_dec(key2, 1)); + + for(size_t i = 2; i != 14; i += 2) + { + __m128i k_t = key2; + key1 = key2 = aes_schedule_round(&rcon, key2, key1); + + _mm_storeu_si128(EK_mm + i, aes_schedule_mangle(key2, i % 4)); + _mm_storeu_si128(DK_mm + (14-i), aes_schedule_mangle_dec(key2, (i+2) % 4)); + + key2 = aes_schedule_round(nullptr, _mm_shuffle_epi32(key2, 0xFF), k_t); + _mm_storeu_si128(EK_mm + i + 1, aes_schedule_mangle(key2, (i - 1) % 4)); + _mm_storeu_si128(DK_mm + (13-i), aes_schedule_mangle_dec(key2, (i+1) % 4)); + } + + key2 = aes_schedule_round(&rcon, key2, key1); + + _mm_storeu_si128(EK_mm + 14, aes_schedule_mangle_last(key2, 2)); + _mm_storeu_si128(DK_mm + 0, aes_schedule_mangle_last_dec(key2)); + } + +void AES_256_SSSE3::clear() + { + zap(EK); + zap(DK); + } + +} diff --git a/src/lib/block/aes_ssse3/aes_ssse3.h b/src/lib/block/aes_ssse3/aes_ssse3.h new file mode 100644 index 000000000..938abeae3 --- /dev/null +++ b/src/lib/block/aes_ssse3/aes_ssse3.h @@ -0,0 +1,71 @@ +/* +* AES using SSSE3 +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_SSSE3_H__ +#define BOTAN_AES_SSSE3_H__ + +#include + +namespace Botan { + +/** +* AES-128 using SSSE3 +*/ +class BOTAN_DLL AES_128_SSSE3 : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "AES-128"; } + BlockCipher* clone() const { return new AES_128_SSSE3; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +/** +* AES-192 using SSSE3 +*/ +class BOTAN_DLL AES_192_SSSE3 : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "AES-192"; } + BlockCipher* clone() const { return new AES_192_SSSE3; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +/** +* AES-256 using SSSE3 +*/ +class BOTAN_DLL AES_256_SSSE3 : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "AES-256"; } + BlockCipher* clone() const { return new AES_256_SSSE3; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +} + +#endif diff --git a/src/lib/block/aes_ssse3/info.txt b/src/lib/block/aes_ssse3/info.txt new file mode 100644 index 000000000..4b1aec535 --- /dev/null +++ b/src/lib/block/aes_ssse3/info.txt @@ -0,0 +1,17 @@ +define AES_SSSE3 20131128 + +load_on auto + +need_isa ssse3 + + +simd_engine + + +# Intel C++ can't deal with syntax for defining constants :( + +gcc +clang +msvc +sunstudio + diff --git a/src/lib/block/block_cipher.h b/src/lib/block/block_cipher.h new file mode 100644 index 000000000..5cbd6bdae --- /dev/null +++ b/src/lib/block/block_cipher.h @@ -0,0 +1,162 @@ +/* +* Block Cipher Base Class +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BLOCK_CIPHER_H__ +#define BOTAN_BLOCK_CIPHER_H__ + +#include + +namespace Botan { + +/** +* This class represents a block cipher object. +*/ +class BOTAN_DLL BlockCipher : public SymmetricAlgorithm + { + public: + + /** + * @return block size of this algorithm + */ + virtual size_t block_size() const = 0; + + /** + * @return native parallelism of this cipher in blocks + */ + virtual size_t parallelism() const { return 1; } + + /** + * @return prefererred parallelism of this cipher in bytes + */ + size_t parallel_bytes() const + { + return parallelism() * block_size() * BOTAN_BLOCK_CIPHER_PAR_MULT; + } + + /** + * Encrypt a block. + * @param in The plaintext block to be encrypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the encrypted block. + * Must be of length block_size(). + */ + void encrypt(const byte in[], byte out[]) const + { encrypt_n(in, out, 1); } + + /** + * Decrypt a block. + * @param in The ciphertext block to be decypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the decrypted block. + * Must be of length block_size(). + */ + void decrypt(const byte in[], byte out[]) const + { decrypt_n(in, out, 1); } + + /** + * Encrypt a block. + * @param block the plaintext block to be encrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void encrypt(byte block[]) const { encrypt_n(block, block, 1); } + + /** + * Decrypt a block. + * @param block the ciphertext block to be decrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void decrypt(byte block[]) const { decrypt_n(block, block, 1); } + + /** + * Encrypt one or more blocks + * @param block the input/output buffer (multiple of block_size()) + */ + template + void encrypt(std::vector& block) const + { + return encrypt_n(&block[0], &block[0], block.size() / block_size()); + } + + /** + * Decrypt one or more blocks + * @param block the input/output buffer (multiple of block_size()) + */ + template + void decrypt(std::vector& block) const + { + return decrypt_n(&block[0], &block[0], block.size() / block_size()); + } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + */ + template + void encrypt(const std::vector& in, + std::vector& out) const + { + return encrypt_n(&in[0], &out[0], in.size() / block_size()); + } + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + */ + template + void decrypt(const std::vector& in, + std::vector& out) const + { + return decrypt_n(&in[0], &out[0], in.size() / block_size()); + } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void encrypt_n(const byte in[], byte out[], + size_t blocks) const = 0; + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void decrypt_n(const byte in[], byte out[], + size_t blocks) const = 0; + + /** + * @return new object representing the same algorithm as *this + */ + virtual BlockCipher* clone() const = 0; + }; + +/** +* Represents a block cipher with a single fixed block size +*/ +template +class Block_Cipher_Fixed_Params : public BlockCipher + { + public: + enum { BLOCK_SIZE = BS }; + size_t block_size() const { return BS; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(KMIN, KMAX, KMOD); + } + }; + +} + +#endif diff --git a/src/lib/block/blowfish/blfs_tab.cpp b/src/lib/block/blowfish/blfs_tab.cpp new file mode 100644 index 000000000..070fa6c69 --- /dev/null +++ b/src/lib/block/blowfish/blfs_tab.cpp @@ -0,0 +1,190 @@ +/* +* S-Box and P-Box Tables for Blowfish +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const u32bit Blowfish::P_INIT[18] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, + 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B }; + +const u32bit Blowfish::S_INIT[1024] = { + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, + 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, + 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, + 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, + 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, + 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, + 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, + 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, + 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, + 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, + 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, + 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, + 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, + 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, + 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, + 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, + 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, + 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, + 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, + 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, + 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, + 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, 0x4B7A70E9, 0xB5B32944, + 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, + 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, + 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, + 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, + 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, + 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, + 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, + 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, + 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, + 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, + 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, + 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, + 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, + 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, + 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, + 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, + 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, + 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, + 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, + 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, + 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, + 0xE6E39F2B, 0xDB83ADF7, 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, + 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, + 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, + 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, + 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, + 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, + 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, + 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, + 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, + 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, + 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, + 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, + 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, + 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, + 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, + 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, + 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, + 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, + 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, + 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, + 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, + 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, + 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, + 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, + 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, + 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, + 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, + 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, + 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, + 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, + 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, + 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, + 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, + 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, + 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, + 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, + 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, + 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, + 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, + 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, + 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, + 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, + 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 }; + +} diff --git a/src/lib/block/blowfish/blowfish.cpp b/src/lib/block/blowfish/blowfish.cpp new file mode 100644 index 000000000..e93359141 --- /dev/null +++ b/src/lib/block/blowfish/blowfish.cpp @@ -0,0 +1,195 @@ +/* +* Blowfish +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Blowfish Encryption +*/ +void Blowfish::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 0; j != 16; j += 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j+1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + L ^= P[16]; R ^= P[17]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Blowfish Decryption +*/ +void Blowfish::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 17; j != 1; j -= 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j-1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + L ^= P[1]; R ^= P[0]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Blowfish Key Schedule +*/ +void Blowfish::key_schedule(const byte key[], size_t length) + { + P.resize(18); + std::copy(P_INIT, P_INIT + 18, P.begin()); + + S.resize(1024); + std::copy(S_INIT, S_INIT + 1024, S.begin()); + + const byte null_salt[16] = { 0 }; + + key_expansion(key, length, null_salt); + } + +void Blowfish::key_expansion(const byte key[], + size_t length, + const byte salt[16]) + { + for(size_t i = 0, j = 0; i != 18; ++i, j += 4) + P[i] ^= make_u32bit(key[(j ) % length], key[(j+1) % length], + key[(j+2) % length], key[(j+3) % length]); + + u32bit L = 0, R = 0; + generate_sbox(P, L, R, salt, 0); + generate_sbox(S, L, R, salt, 2); + } + +/* +* Modified key schedule used for bcrypt password hashing +*/ +void Blowfish::eks_key_schedule(const byte key[], size_t length, + const byte salt[16], size_t workfactor) + { + // Truncate longer passwords to the 56 byte limit Blowfish enforces + length = std::min(length, 55); + + if(workfactor == 0) + throw std::invalid_argument("Bcrypt work factor must be at least 1"); + + /* + * On a 2.8 GHz Core-i7, workfactor == 18 takes about 25 seconds to + * hash a password. This seems like a reasonable upper bound for the + * time being. + */ + if(workfactor > 18) + throw std::invalid_argument("Requested Bcrypt work factor " + + std::to_string(workfactor) + " too large"); + + P.resize(18); + std::copy(P_INIT, P_INIT + 18, P.begin()); + + S.resize(1024); + std::copy(S_INIT, S_INIT + 1024, S.begin()); + + key_expansion(key, length, salt); + + const byte null_salt[16] = { 0 }; + const size_t rounds = 1 << workfactor; + + for(size_t r = 0; r != rounds; ++r) + { + key_expansion(key, length, null_salt); + key_expansion(salt, 16, null_salt); + } + } + +/* +* Generate one of the Sboxes +*/ +void Blowfish::generate_sbox(secure_vector& box, + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != box.size(); i += 2) + { + L ^= load_be(salt, (i + salt_off) % 4); + R ^= load_be(salt, (i + salt_off + 1) % 4); + + for(size_t j = 0; j != 16; j += 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j+1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + u32bit T = R; R = L ^ P[16]; L = T ^ P[17]; + box[i] = L; + box[i+1] = R; + } + } + +/* +* Clear memory of sensitive data +*/ +void Blowfish::clear() + { + zap(P); + zap(S); + } + +} diff --git a/src/lib/block/blowfish/blowfish.h b/src/lib/block/blowfish/blowfish.h new file mode 100644 index 000000000..cdf65f285 --- /dev/null +++ b/src/lib/block/blowfish/blowfish.h @@ -0,0 +1,53 @@ +/* +* Blowfish +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BLOWFISH_H__ +#define BOTAN_BLOWFISH_H__ + +#include + +namespace Botan { + +/** +* Blowfish +*/ +class BOTAN_DLL Blowfish : public Block_Cipher_Fixed_Params<8, 1, 56> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + /** + * Modified EKSBlowfish key schedule, used for bcrypt password hashing + */ + void eks_key_schedule(const byte key[], size_t key_length, + const byte salt[16], size_t workfactor); + + void clear(); + std::string name() const { return "Blowfish"; } + BlockCipher* clone() const { return new Blowfish; } + private: + void key_schedule(const byte key[], size_t length); + + void key_expansion(const byte key[], + size_t key_length, + const byte salt[16]); + + void generate_sbox(secure_vector& box, + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const; + + static const u32bit P_INIT[18]; + static const u32bit S_INIT[1024]; + + secure_vector S, P; + }; + +} + +#endif diff --git a/src/lib/block/blowfish/info.txt b/src/lib/block/blowfish/info.txt new file mode 100644 index 000000000..1a33140d3 --- /dev/null +++ b/src/lib/block/blowfish/info.txt @@ -0,0 +1 @@ +define BLOWFISH 20131128 diff --git a/src/lib/block/camellia/camellia.cpp b/src/lib/block/camellia/camellia.cpp new file mode 100644 index 000000000..a5d70d736 --- /dev/null +++ b/src/lib/block/camellia/camellia.cpp @@ -0,0 +1,394 @@ +/* +* Camellia +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace Camellia_F { + +namespace { + +/* +* We use the slow byte-wise version of F in the first and last rounds +* to help protect against timing attacks +*/ +u64bit F_SLOW(u64bit v, u64bit K) + { + static const byte SBOX[256] = { + 0x70, 0x82, 0x2C, 0xEC, 0xB3, 0x27, 0xC0, 0xE5, 0xE4, 0x85, 0x57, + 0x35, 0xEA, 0x0C, 0xAE, 0x41, 0x23, 0xEF, 0x6B, 0x93, 0x45, 0x19, + 0xA5, 0x21, 0xED, 0x0E, 0x4F, 0x4E, 0x1D, 0x65, 0x92, 0xBD, 0x86, + 0xB8, 0xAF, 0x8F, 0x7C, 0xEB, 0x1F, 0xCE, 0x3E, 0x30, 0xDC, 0x5F, + 0x5E, 0xC5, 0x0B, 0x1A, 0xA6, 0xE1, 0x39, 0xCA, 0xD5, 0x47, 0x5D, + 0x3D, 0xD9, 0x01, 0x5A, 0xD6, 0x51, 0x56, 0x6C, 0x4D, 0x8B, 0x0D, + 0x9A, 0x66, 0xFB, 0xCC, 0xB0, 0x2D, 0x74, 0x12, 0x2B, 0x20, 0xF0, + 0xB1, 0x84, 0x99, 0xDF, 0x4C, 0xCB, 0xC2, 0x34, 0x7E, 0x76, 0x05, + 0x6D, 0xB7, 0xA9, 0x31, 0xD1, 0x17, 0x04, 0xD7, 0x14, 0x58, 0x3A, + 0x61, 0xDE, 0x1B, 0x11, 0x1C, 0x32, 0x0F, 0x9C, 0x16, 0x53, 0x18, + 0xF2, 0x22, 0xFE, 0x44, 0xCF, 0xB2, 0xC3, 0xB5, 0x7A, 0x91, 0x24, + 0x08, 0xE8, 0xA8, 0x60, 0xFC, 0x69, 0x50, 0xAA, 0xD0, 0xA0, 0x7D, + 0xA1, 0x89, 0x62, 0x97, 0x54, 0x5B, 0x1E, 0x95, 0xE0, 0xFF, 0x64, + 0xD2, 0x10, 0xC4, 0x00, 0x48, 0xA3, 0xF7, 0x75, 0xDB, 0x8A, 0x03, + 0xE6, 0xDA, 0x09, 0x3F, 0xDD, 0x94, 0x87, 0x5C, 0x83, 0x02, 0xCD, + 0x4A, 0x90, 0x33, 0x73, 0x67, 0xF6, 0xF3, 0x9D, 0x7F, 0xBF, 0xE2, + 0x52, 0x9B, 0xD8, 0x26, 0xC8, 0x37, 0xC6, 0x3B, 0x81, 0x96, 0x6F, + 0x4B, 0x13, 0xBE, 0x63, 0x2E, 0xE9, 0x79, 0xA7, 0x8C, 0x9F, 0x6E, + 0xBC, 0x8E, 0x29, 0xF5, 0xF9, 0xB6, 0x2F, 0xFD, 0xB4, 0x59, 0x78, + 0x98, 0x06, 0x6A, 0xE7, 0x46, 0x71, 0xBA, 0xD4, 0x25, 0xAB, 0x42, + 0x88, 0xA2, 0x8D, 0xFA, 0x72, 0x07, 0xB9, 0x55, 0xF8, 0xEE, 0xAC, + 0x0A, 0x36, 0x49, 0x2A, 0x68, 0x3C, 0x38, 0xF1, 0xA4, 0x40, 0x28, + 0xD3, 0x7B, 0xBB, 0xC9, 0x43, 0xC1, 0x15, 0xE3, 0xAD, 0xF4, 0x77, + 0xC7, 0x80, 0x9E }; + + const u64bit x = v ^ K; + + const byte t1 = SBOX[get_byte(0, x)]; + const byte t2 = rotate_left(SBOX[get_byte(1, x)], 1); + const byte t3 = rotate_left(SBOX[get_byte(2, x)], 7); + const byte t4 = SBOX[rotate_left(get_byte(3, x), 1)]; + const byte t5 = rotate_left(SBOX[get_byte(4, x)], 1); + const byte t6 = rotate_left(SBOX[get_byte(5, x)], 7); + const byte t7 = SBOX[rotate_left(get_byte(6, x), 1)]; + const byte t8 = SBOX[get_byte(7, x)]; + + const byte y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; + const byte y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; + const byte y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; + const byte y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; + const byte y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; + const byte y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; + const byte y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; + const byte y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; + + return make_u64bit(y1, y2, y3, y4, y5, y6, y7, y8); + } + +inline u64bit F(u64bit v, u64bit K) + { + const u64bit x = v ^ K; + + return Camellia_SBOX1[get_byte(0, x)] ^ + Camellia_SBOX2[get_byte(1, x)] ^ + Camellia_SBOX3[get_byte(2, x)] ^ + Camellia_SBOX4[get_byte(3, x)] ^ + Camellia_SBOX5[get_byte(4, x)] ^ + Camellia_SBOX6[get_byte(5, x)] ^ + Camellia_SBOX7[get_byte(6, x)] ^ + Camellia_SBOX8[get_byte(7, x)]; + } + +inline u64bit FL(u64bit v, u64bit K) + { + u32bit x1 = (v >> 32); + u32bit x2 = (v & 0xFFFFFFFF); + + const u32bit k1 = (K >> 32); + const u32bit k2 = (K & 0xFFFFFFFF); + + x2 ^= rotate_left(x1 & k1, 1); + x1 ^= (x2 | k2); + + return ((static_cast(x1) << 32) | x2); + } + +inline u64bit FLINV(u64bit v, u64bit K) + { + u32bit x1 = (v >> 32); + u32bit x2 = (v & 0xFFFFFFFF); + + const u32bit k1 = (K >> 32); + const u32bit k2 = (K & 0xFFFFFFFF); + + x1 ^= (x2 | k2); + x2 ^= rotate_left(x1 & k1, 1); + + return ((static_cast(x1) << 32) | x2); + } + +/* +* Camellia Encryption +*/ +void encrypt(const byte in[], byte out[], size_t blocks, + const secure_vector& SK, const size_t rounds) + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit D1 = load_be(in, 0); + u64bit D2 = load_be(in, 1); + + const u64bit* K = &SK[0]; + + D1 ^= *K++; + D2 ^= *K++; + + D2 ^= F_SLOW(D1, *K++); + D1 ^= F_SLOW(D2, *K++); + + for(size_t r = 1; r != rounds - 1; ++r) + { + if(r % 3 == 0) + { + D1 = FL (D1, *K++); + D2 = FLINV(D2, *K++); + } + + D2 ^= F(D1, *K++); + D1 ^= F(D2, *K++); + } + + D2 ^= F_SLOW(D1, *K++); + D1 ^= F_SLOW(D2, *K++); + + D2 ^= *K++; + D1 ^= *K++; + + store_be(out, D2, D1); + + in += 16; + out += 16; + } + } + +/* +* Camellia Decryption +*/ +void decrypt(const byte in[], byte out[], size_t blocks, + const secure_vector& SK, const size_t rounds) + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit D1 = load_be(in, 0); + u64bit D2 = load_be(in, 1); + + const u64bit* K = &SK[SK.size()-1]; + + D2 ^= *K--; + D1 ^= *K--; + + D2 ^= F_SLOW(D1, *K--); + D1 ^= F_SLOW(D2, *K--); + + for(size_t r = 1; r != rounds - 1; ++r) + { + if(r % 3 == 0) + { + D1 = FL (D1, *K--); + D2 = FLINV(D2, *K--); + } + + D2 ^= F(D1, *K--); + D1 ^= F(D2, *K--); + } + + D2 ^= F_SLOW(D1, *K--); + D1 ^= F_SLOW(D2, *K--); + + D1 ^= *K--; + D2 ^= *K; + + store_be(out, D2, D1); + + in += 16; + out += 16; + } + } + +u64bit left_rot_hi(u64bit h, u64bit l, size_t shift) + { + return (h << shift) | ((l >> (64-shift))); + } + +u64bit left_rot_lo(u64bit h, u64bit l, size_t shift) + { + return (h >> (64-shift)) | (l << shift); + } + +/* +* Camellia Key Schedule +*/ +void key_schedule(secure_vector& SK, const byte key[], size_t length) + { + const u64bit Sigma1 = 0xA09E667F3BCC908B; + const u64bit Sigma2 = 0xB67AE8584CAA73B2; + const u64bit Sigma3 = 0xC6EF372FE94F82BE; + const u64bit Sigma4 = 0x54FF53A5F1D36F1C; + const u64bit Sigma5 = 0x10E527FADE682D1D; + const u64bit Sigma6 = 0xB05688C2B3E6C1FD; + + const u64bit KL_H = load_be(key, 0); + const u64bit KL_L = load_be(key, 1); + + const u64bit KR_H = (length >= 24) ? load_be(key, 2) : 0; + const u64bit KR_L = + (length == 32) ? load_be(key, 3) : ((length == 24) ? ~KR_H : 0); + + u64bit D1 = KL_H ^ KR_H; + u64bit D2 = KL_L ^ KR_L; + D2 ^= F(D1, Sigma1); + D1 ^= F(D2, Sigma2); + D1 ^= KL_H; + D2 ^= KL_L; + D2 ^= F(D1, Sigma3); + D1 ^= F(D2, Sigma4); + + const u64bit KA_H = D1; + const u64bit KA_L = D2; + + D1 = KA_H ^ KR_H; + D2 = KA_L ^ KR_L; + D2 ^= F(D1, Sigma5); + D1 ^= F(D2, Sigma6); + + const u64bit KB_H = D1; + const u64bit KB_L = D2; + + if(length == 16) + { + SK.resize(26); + + SK[ 0] = KL_H; + SK[ 1] = KL_L; + SK[ 2] = KA_H; + SK[ 3] = KA_L; + SK[ 4] = left_rot_hi(KL_H, KL_L, 15); + SK[ 5] = left_rot_lo(KL_H, KL_L, 15); + SK[ 6] = left_rot_hi(KA_H, KA_L, 15); + SK[ 7] = left_rot_lo(KA_H, KA_L, 15); + SK[ 8] = left_rot_hi(KA_H, KA_L, 30); + SK[ 9] = left_rot_lo(KA_H, KA_L, 30); + SK[10] = left_rot_hi(KL_H, KL_L, 45); + SK[11] = left_rot_lo(KL_H, KL_L, 45); + SK[12] = left_rot_hi(KA_H, KA_L, 45); + SK[13] = left_rot_lo(KL_H, KL_L, 60); + SK[14] = left_rot_hi(KA_H, KA_L, 60); + SK[15] = left_rot_lo(KA_H, KA_L, 60); + SK[16] = left_rot_lo(KL_H, KL_L, 77-64); + SK[17] = left_rot_hi(KL_H, KL_L, 77-64); + SK[18] = left_rot_lo(KL_H, KL_L, 94-64); + SK[19] = left_rot_hi(KL_H, KL_L, 94-64); + SK[20] = left_rot_lo(KA_H, KA_L, 94-64); + SK[21] = left_rot_hi(KA_H, KA_L, 94-64); + SK[22] = left_rot_lo(KL_H, KL_L, 111-64); + SK[23] = left_rot_hi(KL_H, KL_L, 111-64); + SK[24] = left_rot_lo(KA_H, KA_L, 111-64); + SK[25] = left_rot_hi(KA_H, KA_L, 111-64); + } + else + { + SK.resize(34); + + SK[ 0] = KL_H; + SK[ 1] = KL_L; + SK[ 2] = KB_H; + SK[ 3] = KB_L; + + SK[ 4] = left_rot_hi(KR_H, KR_L, 15); + SK[ 5] = left_rot_lo(KR_H, KR_L, 15); + SK[ 6] = left_rot_hi(KA_H, KA_L, 15); + SK[ 7] = left_rot_lo(KA_H, KA_L, 15); + + SK[ 8] = left_rot_hi(KR_H, KR_L, 30); + SK[ 9] = left_rot_lo(KR_H, KR_L, 30); + SK[10] = left_rot_hi(KB_H, KB_L, 30); + SK[11] = left_rot_lo(KB_H, KB_L, 30); + + SK[12] = left_rot_hi(KL_H, KL_L, 45); + SK[13] = left_rot_lo(KL_H, KL_L, 45); + SK[14] = left_rot_hi(KA_H, KA_L, 45); + SK[15] = left_rot_lo(KA_H, KA_L, 45); + + SK[16] = left_rot_hi(KL_H, KL_L, 60); + SK[17] = left_rot_lo(KL_H, KL_L, 60); + SK[18] = left_rot_hi(KR_H, KR_L, 60); + SK[19] = left_rot_lo(KR_H, KR_L, 60); + SK[20] = left_rot_hi(KB_H, KB_L, 60); + SK[21] = left_rot_lo(KB_H, KB_L, 60); + + SK[22] = left_rot_lo(KL_H, KL_L, 77-64); + SK[23] = left_rot_hi(KL_H, KL_L, 77-64); + SK[24] = left_rot_lo(KA_H, KA_L, 77-64); + SK[25] = left_rot_hi(KA_H, KA_L, 77-64); + + SK[26] = left_rot_lo(KR_H, KR_L, 94-64); + SK[27] = left_rot_hi(KR_H, KR_L, 94-64); + SK[28] = left_rot_lo(KA_H, KA_L, 94-64); + SK[29] = left_rot_hi(KA_H, KA_L, 94-64); + SK[30] = left_rot_lo(KL_H, KL_L, 111-64); + SK[31] = left_rot_hi(KL_H, KL_L, 111-64); + SK[32] = left_rot_lo(KB_H, KB_L, 111-64); + SK[33] = left_rot_hi(KB_H, KB_L, 111-64); + } + } + +} + +} + +void Camellia_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK, 9); + } + +void Camellia_192::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK, 12); + } + +void Camellia_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK, 12); + } + +void Camellia_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK, 9); + } + +void Camellia_192::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK, 12); + } + +void Camellia_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK, 12); + } + +void Camellia_128::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_192::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_256::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_128::clear() + { + zap(SK); + } + +void Camellia_192::clear() + { + zap(SK); + } + +void Camellia_256::clear() + { + zap(SK); + } + +} diff --git a/src/lib/block/camellia/camellia.h b/src/lib/block/camellia/camellia.h new file mode 100644 index 000000000..09f420765 --- /dev/null +++ b/src/lib/block/camellia/camellia.h @@ -0,0 +1,71 @@ +/* +* Camellia +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CAMELLIA_H__ +#define BOTAN_CAMELLIA_H__ + +#include + +namespace Botan { + +/** +* Camellia-128 +*/ +class BOTAN_DLL Camellia_128 : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Camellia-128"; } + BlockCipher* clone() const { return new Camellia_128; } + private: + void key_schedule(const byte key[], size_t length); + + secure_vector SK; + }; + +/** +* Camellia-192 +*/ +class BOTAN_DLL Camellia_192 : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Camellia-192"; } + BlockCipher* clone() const { return new Camellia_192; } + private: + void key_schedule(const byte key[], size_t length); + + secure_vector SK; + }; + +/** +* Camellia-256 +*/ +class BOTAN_DLL Camellia_256 : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Camellia-256"; } + BlockCipher* clone() const { return new Camellia_256; } + private: + void key_schedule(const byte key[], size_t length); + + secure_vector SK; + }; + +} + +#endif diff --git a/src/lib/block/camellia/camellia_sbox.h b/src/lib/block/camellia/camellia_sbox.h new file mode 100644 index 000000000..24c849a16 --- /dev/null +++ b/src/lib/block/camellia/camellia_sbox.h @@ -0,0 +1,545 @@ +/* +* Camellia SBox Tables +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CAMELLIA_SBOX_H__ +#define BOTAN_CAMELLIA_SBOX_H__ + +#include + +namespace Botan { + +const u64bit Camellia_SBOX1[256] = { +0x7070700070000070, 0x8282820082000082, 0x2C2C2C002C00002C, 0xECECEC00EC0000EC, +0xB3B3B300B30000B3, 0x2727270027000027, 0xC0C0C000C00000C0, 0xE5E5E500E50000E5, +0xE4E4E400E40000E4, 0x8585850085000085, 0x5757570057000057, 0x3535350035000035, +0xEAEAEA00EA0000EA, 0x0C0C0C000C00000C, 0xAEAEAE00AE0000AE, 0x4141410041000041, +0x2323230023000023, 0xEFEFEF00EF0000EF, 0x6B6B6B006B00006B, 0x9393930093000093, +0x4545450045000045, 0x1919190019000019, 0xA5A5A500A50000A5, 0x2121210021000021, +0xEDEDED00ED0000ED, 0x0E0E0E000E00000E, 0x4F4F4F004F00004F, 0x4E4E4E004E00004E, +0x1D1D1D001D00001D, 0x6565650065000065, 0x9292920092000092, 0xBDBDBD00BD0000BD, +0x8686860086000086, 0xB8B8B800B80000B8, 0xAFAFAF00AF0000AF, 0x8F8F8F008F00008F, +0x7C7C7C007C00007C, 0xEBEBEB00EB0000EB, 0x1F1F1F001F00001F, 0xCECECE00CE0000CE, +0x3E3E3E003E00003E, 0x3030300030000030, 0xDCDCDC00DC0000DC, 0x5F5F5F005F00005F, +0x5E5E5E005E00005E, 0xC5C5C500C50000C5, 0x0B0B0B000B00000B, 0x1A1A1A001A00001A, +0xA6A6A600A60000A6, 0xE1E1E100E10000E1, 0x3939390039000039, 0xCACACA00CA0000CA, +0xD5D5D500D50000D5, 0x4747470047000047, 0x5D5D5D005D00005D, 0x3D3D3D003D00003D, +0xD9D9D900D90000D9, 0x0101010001000001, 0x5A5A5A005A00005A, 0xD6D6D600D60000D6, +0x5151510051000051, 0x5656560056000056, 0x6C6C6C006C00006C, 0x4D4D4D004D00004D, +0x8B8B8B008B00008B, 0x0D0D0D000D00000D, 0x9A9A9A009A00009A, 0x6666660066000066, +0xFBFBFB00FB0000FB, 0xCCCCCC00CC0000CC, 0xB0B0B000B00000B0, 0x2D2D2D002D00002D, +0x7474740074000074, 0x1212120012000012, 0x2B2B2B002B00002B, 0x2020200020000020, +0xF0F0F000F00000F0, 0xB1B1B100B10000B1, 0x8484840084000084, 0x9999990099000099, +0xDFDFDF00DF0000DF, 0x4C4C4C004C00004C, 0xCBCBCB00CB0000CB, 0xC2C2C200C20000C2, +0x3434340034000034, 0x7E7E7E007E00007E, 0x7676760076000076, 0x0505050005000005, +0x6D6D6D006D00006D, 0xB7B7B700B70000B7, 0xA9A9A900A90000A9, 0x3131310031000031, +0xD1D1D100D10000D1, 0x1717170017000017, 0x0404040004000004, 0xD7D7D700D70000D7, +0x1414140014000014, 0x5858580058000058, 0x3A3A3A003A00003A, 0x6161610061000061, +0xDEDEDE00DE0000DE, 0x1B1B1B001B00001B, 0x1111110011000011, 0x1C1C1C001C00001C, +0x3232320032000032, 0x0F0F0F000F00000F, 0x9C9C9C009C00009C, 0x1616160016000016, +0x5353530053000053, 0x1818180018000018, 0xF2F2F200F20000F2, 0x2222220022000022, +0xFEFEFE00FE0000FE, 0x4444440044000044, 0xCFCFCF00CF0000CF, 0xB2B2B200B20000B2, +0xC3C3C300C30000C3, 0xB5B5B500B50000B5, 0x7A7A7A007A00007A, 0x9191910091000091, +0x2424240024000024, 0x0808080008000008, 0xE8E8E800E80000E8, 0xA8A8A800A80000A8, +0x6060600060000060, 0xFCFCFC00FC0000FC, 0x6969690069000069, 0x5050500050000050, +0xAAAAAA00AA0000AA, 0xD0D0D000D00000D0, 0xA0A0A000A00000A0, 0x7D7D7D007D00007D, +0xA1A1A100A10000A1, 0x8989890089000089, 0x6262620062000062, 0x9797970097000097, +0x5454540054000054, 0x5B5B5B005B00005B, 0x1E1E1E001E00001E, 0x9595950095000095, +0xE0E0E000E00000E0, 0xFFFFFF00FF0000FF, 0x6464640064000064, 0xD2D2D200D20000D2, +0x1010100010000010, 0xC4C4C400C40000C4, 0x0000000000000000, 0x4848480048000048, +0xA3A3A300A30000A3, 0xF7F7F700F70000F7, 0x7575750075000075, 0xDBDBDB00DB0000DB, +0x8A8A8A008A00008A, 0x0303030003000003, 0xE6E6E600E60000E6, 0xDADADA00DA0000DA, +0x0909090009000009, 0x3F3F3F003F00003F, 0xDDDDDD00DD0000DD, 0x9494940094000094, +0x8787870087000087, 0x5C5C5C005C00005C, 0x8383830083000083, 0x0202020002000002, +0xCDCDCD00CD0000CD, 0x4A4A4A004A00004A, 0x9090900090000090, 0x3333330033000033, +0x7373730073000073, 0x6767670067000067, 0xF6F6F600F60000F6, 0xF3F3F300F30000F3, +0x9D9D9D009D00009D, 0x7F7F7F007F00007F, 0xBFBFBF00BF0000BF, 0xE2E2E200E20000E2, +0x5252520052000052, 0x9B9B9B009B00009B, 0xD8D8D800D80000D8, 0x2626260026000026, +0xC8C8C800C80000C8, 0x3737370037000037, 0xC6C6C600C60000C6, 0x3B3B3B003B00003B, +0x8181810081000081, 0x9696960096000096, 0x6F6F6F006F00006F, 0x4B4B4B004B00004B, +0x1313130013000013, 0xBEBEBE00BE0000BE, 0x6363630063000063, 0x2E2E2E002E00002E, +0xE9E9E900E90000E9, 0x7979790079000079, 0xA7A7A700A70000A7, 0x8C8C8C008C00008C, +0x9F9F9F009F00009F, 0x6E6E6E006E00006E, 0xBCBCBC00BC0000BC, 0x8E8E8E008E00008E, +0x2929290029000029, 0xF5F5F500F50000F5, 0xF9F9F900F90000F9, 0xB6B6B600B60000B6, +0x2F2F2F002F00002F, 0xFDFDFD00FD0000FD, 0xB4B4B400B40000B4, 0x5959590059000059, +0x7878780078000078, 0x9898980098000098, 0x0606060006000006, 0x6A6A6A006A00006A, +0xE7E7E700E70000E7, 0x4646460046000046, 0x7171710071000071, 0xBABABA00BA0000BA, +0xD4D4D400D40000D4, 0x2525250025000025, 0xABABAB00AB0000AB, 0x4242420042000042, +0x8888880088000088, 0xA2A2A200A20000A2, 0x8D8D8D008D00008D, 0xFAFAFA00FA0000FA, +0x7272720072000072, 0x0707070007000007, 0xB9B9B900B90000B9, 0x5555550055000055, +0xF8F8F800F80000F8, 0xEEEEEE00EE0000EE, 0xACACAC00AC0000AC, 0x0A0A0A000A00000A, +0x3636360036000036, 0x4949490049000049, 0x2A2A2A002A00002A, 0x6868680068000068, +0x3C3C3C003C00003C, 0x3838380038000038, 0xF1F1F100F10000F1, 0xA4A4A400A40000A4, +0x4040400040000040, 0x2828280028000028, 0xD3D3D300D30000D3, 0x7B7B7B007B00007B, +0xBBBBBB00BB0000BB, 0xC9C9C900C90000C9, 0x4343430043000043, 0xC1C1C100C10000C1, +0x1515150015000015, 0xE3E3E300E30000E3, 0xADADAD00AD0000AD, 0xF4F4F400F40000F4, +0x7777770077000077, 0xC7C7C700C70000C7, 0x8080800080000080, 0x9E9E9E009E00009E }; + +const u64bit Camellia_SBOX2[256] = { +0x00E0E0E0E0E00000, 0x0005050505050000, 0x0058585858580000, 0x00D9D9D9D9D90000, +0x0067676767670000, 0x004E4E4E4E4E0000, 0x0081818181810000, 0x00CBCBCBCBCB0000, +0x00C9C9C9C9C90000, 0x000B0B0B0B0B0000, 0x00AEAEAEAEAE0000, 0x006A6A6A6A6A0000, +0x00D5D5D5D5D50000, 0x0018181818180000, 0x005D5D5D5D5D0000, 0x0082828282820000, +0x0046464646460000, 0x00DFDFDFDFDF0000, 0x00D6D6D6D6D60000, 0x0027272727270000, +0x008A8A8A8A8A0000, 0x0032323232320000, 0x004B4B4B4B4B0000, 0x0042424242420000, +0x00DBDBDBDBDB0000, 0x001C1C1C1C1C0000, 0x009E9E9E9E9E0000, 0x009C9C9C9C9C0000, +0x003A3A3A3A3A0000, 0x00CACACACACA0000, 0x0025252525250000, 0x007B7B7B7B7B0000, +0x000D0D0D0D0D0000, 0x0071717171710000, 0x005F5F5F5F5F0000, 0x001F1F1F1F1F0000, +0x00F8F8F8F8F80000, 0x00D7D7D7D7D70000, 0x003E3E3E3E3E0000, 0x009D9D9D9D9D0000, +0x007C7C7C7C7C0000, 0x0060606060600000, 0x00B9B9B9B9B90000, 0x00BEBEBEBEBE0000, +0x00BCBCBCBCBC0000, 0x008B8B8B8B8B0000, 0x0016161616160000, 0x0034343434340000, +0x004D4D4D4D4D0000, 0x00C3C3C3C3C30000, 0x0072727272720000, 0x0095959595950000, +0x00ABABABABAB0000, 0x008E8E8E8E8E0000, 0x00BABABABABA0000, 0x007A7A7A7A7A0000, +0x00B3B3B3B3B30000, 0x0002020202020000, 0x00B4B4B4B4B40000, 0x00ADADADADAD0000, +0x00A2A2A2A2A20000, 0x00ACACACACAC0000, 0x00D8D8D8D8D80000, 0x009A9A9A9A9A0000, +0x0017171717170000, 0x001A1A1A1A1A0000, 0x0035353535350000, 0x00CCCCCCCCCC0000, +0x00F7F7F7F7F70000, 0x0099999999990000, 0x0061616161610000, 0x005A5A5A5A5A0000, +0x00E8E8E8E8E80000, 0x0024242424240000, 0x0056565656560000, 0x0040404040400000, +0x00E1E1E1E1E10000, 0x0063636363630000, 0x0009090909090000, 0x0033333333330000, +0x00BFBFBFBFBF0000, 0x0098989898980000, 0x0097979797970000, 0x0085858585850000, +0x0068686868680000, 0x00FCFCFCFCFC0000, 0x00ECECECECEC0000, 0x000A0A0A0A0A0000, +0x00DADADADADA0000, 0x006F6F6F6F6F0000, 0x0053535353530000, 0x0062626262620000, +0x00A3A3A3A3A30000, 0x002E2E2E2E2E0000, 0x0008080808080000, 0x00AFAFAFAFAF0000, +0x0028282828280000, 0x00B0B0B0B0B00000, 0x0074747474740000, 0x00C2C2C2C2C20000, +0x00BDBDBDBDBD0000, 0x0036363636360000, 0x0022222222220000, 0x0038383838380000, +0x0064646464640000, 0x001E1E1E1E1E0000, 0x0039393939390000, 0x002C2C2C2C2C0000, +0x00A6A6A6A6A60000, 0x0030303030300000, 0x00E5E5E5E5E50000, 0x0044444444440000, +0x00FDFDFDFDFD0000, 0x0088888888880000, 0x009F9F9F9F9F0000, 0x0065656565650000, +0x0087878787870000, 0x006B6B6B6B6B0000, 0x00F4F4F4F4F40000, 0x0023232323230000, +0x0048484848480000, 0x0010101010100000, 0x00D1D1D1D1D10000, 0x0051515151510000, +0x00C0C0C0C0C00000, 0x00F9F9F9F9F90000, 0x00D2D2D2D2D20000, 0x00A0A0A0A0A00000, +0x0055555555550000, 0x00A1A1A1A1A10000, 0x0041414141410000, 0x00FAFAFAFAFA0000, +0x0043434343430000, 0x0013131313130000, 0x00C4C4C4C4C40000, 0x002F2F2F2F2F0000, +0x00A8A8A8A8A80000, 0x00B6B6B6B6B60000, 0x003C3C3C3C3C0000, 0x002B2B2B2B2B0000, +0x00C1C1C1C1C10000, 0x00FFFFFFFFFF0000, 0x00C8C8C8C8C80000, 0x00A5A5A5A5A50000, +0x0020202020200000, 0x0089898989890000, 0x0000000000000000, 0x0090909090900000, +0x0047474747470000, 0x00EFEFEFEFEF0000, 0x00EAEAEAEAEA0000, 0x00B7B7B7B7B70000, +0x0015151515150000, 0x0006060606060000, 0x00CDCDCDCDCD0000, 0x00B5B5B5B5B50000, +0x0012121212120000, 0x007E7E7E7E7E0000, 0x00BBBBBBBBBB0000, 0x0029292929290000, +0x000F0F0F0F0F0000, 0x00B8B8B8B8B80000, 0x0007070707070000, 0x0004040404040000, +0x009B9B9B9B9B0000, 0x0094949494940000, 0x0021212121210000, 0x0066666666660000, +0x00E6E6E6E6E60000, 0x00CECECECECE0000, 0x00EDEDEDEDED0000, 0x00E7E7E7E7E70000, +0x003B3B3B3B3B0000, 0x00FEFEFEFEFE0000, 0x007F7F7F7F7F0000, 0x00C5C5C5C5C50000, +0x00A4A4A4A4A40000, 0x0037373737370000, 0x00B1B1B1B1B10000, 0x004C4C4C4C4C0000, +0x0091919191910000, 0x006E6E6E6E6E0000, 0x008D8D8D8D8D0000, 0x0076767676760000, +0x0003030303030000, 0x002D2D2D2D2D0000, 0x00DEDEDEDEDE0000, 0x0096969696960000, +0x0026262626260000, 0x007D7D7D7D7D0000, 0x00C6C6C6C6C60000, 0x005C5C5C5C5C0000, +0x00D3D3D3D3D30000, 0x00F2F2F2F2F20000, 0x004F4F4F4F4F0000, 0x0019191919190000, +0x003F3F3F3F3F0000, 0x00DCDCDCDCDC0000, 0x0079797979790000, 0x001D1D1D1D1D0000, +0x0052525252520000, 0x00EBEBEBEBEB0000, 0x00F3F3F3F3F30000, 0x006D6D6D6D6D0000, +0x005E5E5E5E5E0000, 0x00FBFBFBFBFB0000, 0x0069696969690000, 0x00B2B2B2B2B20000, +0x00F0F0F0F0F00000, 0x0031313131310000, 0x000C0C0C0C0C0000, 0x00D4D4D4D4D40000, +0x00CFCFCFCFCF0000, 0x008C8C8C8C8C0000, 0x00E2E2E2E2E20000, 0x0075757575750000, +0x00A9A9A9A9A90000, 0x004A4A4A4A4A0000, 0x0057575757570000, 0x0084848484840000, +0x0011111111110000, 0x0045454545450000, 0x001B1B1B1B1B0000, 0x00F5F5F5F5F50000, +0x00E4E4E4E4E40000, 0x000E0E0E0E0E0000, 0x0073737373730000, 0x00AAAAAAAAAA0000, +0x00F1F1F1F1F10000, 0x00DDDDDDDDDD0000, 0x0059595959590000, 0x0014141414140000, +0x006C6C6C6C6C0000, 0x0092929292920000, 0x0054545454540000, 0x00D0D0D0D0D00000, +0x0078787878780000, 0x0070707070700000, 0x00E3E3E3E3E30000, 0x0049494949490000, +0x0080808080800000, 0x0050505050500000, 0x00A7A7A7A7A70000, 0x00F6F6F6F6F60000, +0x0077777777770000, 0x0093939393930000, 0x0086868686860000, 0x0083838383830000, +0x002A2A2A2A2A0000, 0x00C7C7C7C7C70000, 0x005B5B5B5B5B0000, 0x00E9E9E9E9E90000, +0x00EEEEEEEEEE0000, 0x008F8F8F8F8F0000, 0x0001010101010000, 0x003D3D3D3D3D0000 }; + +const u64bit Camellia_SBOX3[256] = { +0x3800383800383800, 0x4100414100414100, 0x1600161600161600, 0x7600767600767600, +0xD900D9D900D9D900, 0x9300939300939300, 0x6000606000606000, 0xF200F2F200F2F200, +0x7200727200727200, 0xC200C2C200C2C200, 0xAB00ABAB00ABAB00, 0x9A009A9A009A9A00, +0x7500757500757500, 0x0600060600060600, 0x5700575700575700, 0xA000A0A000A0A000, +0x9100919100919100, 0xF700F7F700F7F700, 0xB500B5B500B5B500, 0xC900C9C900C9C900, +0xA200A2A200A2A200, 0x8C008C8C008C8C00, 0xD200D2D200D2D200, 0x9000909000909000, +0xF600F6F600F6F600, 0x0700070700070700, 0xA700A7A700A7A700, 0x2700272700272700, +0x8E008E8E008E8E00, 0xB200B2B200B2B200, 0x4900494900494900, 0xDE00DEDE00DEDE00, +0x4300434300434300, 0x5C005C5C005C5C00, 0xD700D7D700D7D700, 0xC700C7C700C7C700, +0x3E003E3E003E3E00, 0xF500F5F500F5F500, 0x8F008F8F008F8F00, 0x6700676700676700, +0x1F001F1F001F1F00, 0x1800181800181800, 0x6E006E6E006E6E00, 0xAF00AFAF00AFAF00, +0x2F002F2F002F2F00, 0xE200E2E200E2E200, 0x8500858500858500, 0x0D000D0D000D0D00, +0x5300535300535300, 0xF000F0F000F0F000, 0x9C009C9C009C9C00, 0x6500656500656500, +0xEA00EAEA00EAEA00, 0xA300A3A300A3A300, 0xAE00AEAE00AEAE00, 0x9E009E9E009E9E00, +0xEC00ECEC00ECEC00, 0x8000808000808000, 0x2D002D2D002D2D00, 0x6B006B6B006B6B00, +0xA800A8A800A8A800, 0x2B002B2B002B2B00, 0x3600363600363600, 0xA600A6A600A6A600, +0xC500C5C500C5C500, 0x8600868600868600, 0x4D004D4D004D4D00, 0x3300333300333300, +0xFD00FDFD00FDFD00, 0x6600666600666600, 0x5800585800585800, 0x9600969600969600, +0x3A003A3A003A3A00, 0x0900090900090900, 0x9500959500959500, 0x1000101000101000, +0x7800787800787800, 0xD800D8D800D8D800, 0x4200424200424200, 0xCC00CCCC00CCCC00, +0xEF00EFEF00EFEF00, 0x2600262600262600, 0xE500E5E500E5E500, 0x6100616100616100, +0x1A001A1A001A1A00, 0x3F003F3F003F3F00, 0x3B003B3B003B3B00, 0x8200828200828200, +0xB600B6B600B6B600, 0xDB00DBDB00DBDB00, 0xD400D4D400D4D400, 0x9800989800989800, +0xE800E8E800E8E800, 0x8B008B8B008B8B00, 0x0200020200020200, 0xEB00EBEB00EBEB00, +0x0A000A0A000A0A00, 0x2C002C2C002C2C00, 0x1D001D1D001D1D00, 0xB000B0B000B0B000, +0x6F006F6F006F6F00, 0x8D008D8D008D8D00, 0x8800888800888800, 0x0E000E0E000E0E00, +0x1900191900191900, 0x8700878700878700, 0x4E004E4E004E4E00, 0x0B000B0B000B0B00, +0xA900A9A900A9A900, 0x0C000C0C000C0C00, 0x7900797900797900, 0x1100111100111100, +0x7F007F7F007F7F00, 0x2200222200222200, 0xE700E7E700E7E700, 0x5900595900595900, +0xE100E1E100E1E100, 0xDA00DADA00DADA00, 0x3D003D3D003D3D00, 0xC800C8C800C8C800, +0x1200121200121200, 0x0400040400040400, 0x7400747400747400, 0x5400545400545400, +0x3000303000303000, 0x7E007E7E007E7E00, 0xB400B4B400B4B400, 0x2800282800282800, +0x5500555500555500, 0x6800686800686800, 0x5000505000505000, 0xBE00BEBE00BEBE00, +0xD000D0D000D0D000, 0xC400C4C400C4C400, 0x3100313100313100, 0xCB00CBCB00CBCB00, +0x2A002A2A002A2A00, 0xAD00ADAD00ADAD00, 0x0F000F0F000F0F00, 0xCA00CACA00CACA00, +0x7000707000707000, 0xFF00FFFF00FFFF00, 0x3200323200323200, 0x6900696900696900, +0x0800080800080800, 0x6200626200626200, 0x0000000000000000, 0x2400242400242400, +0xD100D1D100D1D100, 0xFB00FBFB00FBFB00, 0xBA00BABA00BABA00, 0xED00EDED00EDED00, +0x4500454500454500, 0x8100818100818100, 0x7300737300737300, 0x6D006D6D006D6D00, +0x8400848400848400, 0x9F009F9F009F9F00, 0xEE00EEEE00EEEE00, 0x4A004A4A004A4A00, +0xC300C3C300C3C300, 0x2E002E2E002E2E00, 0xC100C1C100C1C100, 0x0100010100010100, +0xE600E6E600E6E600, 0x2500252500252500, 0x4800484800484800, 0x9900999900999900, +0xB900B9B900B9B900, 0xB300B3B300B3B300, 0x7B007B7B007B7B00, 0xF900F9F900F9F900, +0xCE00CECE00CECE00, 0xBF00BFBF00BFBF00, 0xDF00DFDF00DFDF00, 0x7100717100717100, +0x2900292900292900, 0xCD00CDCD00CDCD00, 0x6C006C6C006C6C00, 0x1300131300131300, +0x6400646400646400, 0x9B009B9B009B9B00, 0x6300636300636300, 0x9D009D9D009D9D00, +0xC000C0C000C0C000, 0x4B004B4B004B4B00, 0xB700B7B700B7B700, 0xA500A5A500A5A500, +0x8900898900898900, 0x5F005F5F005F5F00, 0xB100B1B100B1B100, 0x1700171700171700, +0xF400F4F400F4F400, 0xBC00BCBC00BCBC00, 0xD300D3D300D3D300, 0x4600464600464600, +0xCF00CFCF00CFCF00, 0x3700373700373700, 0x5E005E5E005E5E00, 0x4700474700474700, +0x9400949400949400, 0xFA00FAFA00FAFA00, 0xFC00FCFC00FCFC00, 0x5B005B5B005B5B00, +0x9700979700979700, 0xFE00FEFE00FEFE00, 0x5A005A5A005A5A00, 0xAC00ACAC00ACAC00, +0x3C003C3C003C3C00, 0x4C004C4C004C4C00, 0x0300030300030300, 0x3500353500353500, +0xF300F3F300F3F300, 0x2300232300232300, 0xB800B8B800B8B800, 0x5D005D5D005D5D00, +0x6A006A6A006A6A00, 0x9200929200929200, 0xD500D5D500D5D500, 0x2100212100212100, +0x4400444400444400, 0x5100515100515100, 0xC600C6C600C6C600, 0x7D007D7D007D7D00, +0x3900393900393900, 0x8300838300838300, 0xDC00DCDC00DCDC00, 0xAA00AAAA00AAAA00, +0x7C007C7C007C7C00, 0x7700777700777700, 0x5600565600565600, 0x0500050500050500, +0x1B001B1B001B1B00, 0xA400A4A400A4A400, 0x1500151500151500, 0x3400343400343400, +0x1E001E1E001E1E00, 0x1C001C1C001C1C00, 0xF800F8F800F8F800, 0x5200525200525200, +0x2000202000202000, 0x1400141400141400, 0xE900E9E900E9E900, 0xBD00BDBD00BDBD00, +0xDD00DDDD00DDDD00, 0xE400E4E400E4E400, 0xA100A1A100A1A100, 0xE000E0E000E0E000, +0x8A008A8A008A8A00, 0xF100F1F100F1F100, 0xD600D6D600D6D600, 0x7A007A7A007A7A00, +0xBB00BBBB00BBBB00, 0xE300E3E300E3E300, 0x4000404000404000, 0x4F004F4F004F4F00 }; + +const u64bit Camellia_SBOX4[256] = { +0x7070007000007070, 0x2C2C002C00002C2C, 0xB3B300B30000B3B3, 0xC0C000C00000C0C0, +0xE4E400E40000E4E4, 0x5757005700005757, 0xEAEA00EA0000EAEA, 0xAEAE00AE0000AEAE, +0x2323002300002323, 0x6B6B006B00006B6B, 0x4545004500004545, 0xA5A500A50000A5A5, +0xEDED00ED0000EDED, 0x4F4F004F00004F4F, 0x1D1D001D00001D1D, 0x9292009200009292, +0x8686008600008686, 0xAFAF00AF0000AFAF, 0x7C7C007C00007C7C, 0x1F1F001F00001F1F, +0x3E3E003E00003E3E, 0xDCDC00DC0000DCDC, 0x5E5E005E00005E5E, 0x0B0B000B00000B0B, +0xA6A600A60000A6A6, 0x3939003900003939, 0xD5D500D50000D5D5, 0x5D5D005D00005D5D, +0xD9D900D90000D9D9, 0x5A5A005A00005A5A, 0x5151005100005151, 0x6C6C006C00006C6C, +0x8B8B008B00008B8B, 0x9A9A009A00009A9A, 0xFBFB00FB0000FBFB, 0xB0B000B00000B0B0, +0x7474007400007474, 0x2B2B002B00002B2B, 0xF0F000F00000F0F0, 0x8484008400008484, +0xDFDF00DF0000DFDF, 0xCBCB00CB0000CBCB, 0x3434003400003434, 0x7676007600007676, +0x6D6D006D00006D6D, 0xA9A900A90000A9A9, 0xD1D100D10000D1D1, 0x0404000400000404, +0x1414001400001414, 0x3A3A003A00003A3A, 0xDEDE00DE0000DEDE, 0x1111001100001111, +0x3232003200003232, 0x9C9C009C00009C9C, 0x5353005300005353, 0xF2F200F20000F2F2, +0xFEFE00FE0000FEFE, 0xCFCF00CF0000CFCF, 0xC3C300C30000C3C3, 0x7A7A007A00007A7A, +0x2424002400002424, 0xE8E800E80000E8E8, 0x6060006000006060, 0x6969006900006969, +0xAAAA00AA0000AAAA, 0xA0A000A00000A0A0, 0xA1A100A10000A1A1, 0x6262006200006262, +0x5454005400005454, 0x1E1E001E00001E1E, 0xE0E000E00000E0E0, 0x6464006400006464, +0x1010001000001010, 0x0000000000000000, 0xA3A300A30000A3A3, 0x7575007500007575, +0x8A8A008A00008A8A, 0xE6E600E60000E6E6, 0x0909000900000909, 0xDDDD00DD0000DDDD, +0x8787008700008787, 0x8383008300008383, 0xCDCD00CD0000CDCD, 0x9090009000009090, +0x7373007300007373, 0xF6F600F60000F6F6, 0x9D9D009D00009D9D, 0xBFBF00BF0000BFBF, +0x5252005200005252, 0xD8D800D80000D8D8, 0xC8C800C80000C8C8, 0xC6C600C60000C6C6, +0x8181008100008181, 0x6F6F006F00006F6F, 0x1313001300001313, 0x6363006300006363, +0xE9E900E90000E9E9, 0xA7A700A70000A7A7, 0x9F9F009F00009F9F, 0xBCBC00BC0000BCBC, +0x2929002900002929, 0xF9F900F90000F9F9, 0x2F2F002F00002F2F, 0xB4B400B40000B4B4, +0x7878007800007878, 0x0606000600000606, 0xE7E700E70000E7E7, 0x7171007100007171, +0xD4D400D40000D4D4, 0xABAB00AB0000ABAB, 0x8888008800008888, 0x8D8D008D00008D8D, +0x7272007200007272, 0xB9B900B90000B9B9, 0xF8F800F80000F8F8, 0xACAC00AC0000ACAC, +0x3636003600003636, 0x2A2A002A00002A2A, 0x3C3C003C00003C3C, 0xF1F100F10000F1F1, +0x4040004000004040, 0xD3D300D30000D3D3, 0xBBBB00BB0000BBBB, 0x4343004300004343, +0x1515001500001515, 0xADAD00AD0000ADAD, 0x7777007700007777, 0x8080008000008080, +0x8282008200008282, 0xECEC00EC0000ECEC, 0x2727002700002727, 0xE5E500E50000E5E5, +0x8585008500008585, 0x3535003500003535, 0x0C0C000C00000C0C, 0x4141004100004141, +0xEFEF00EF0000EFEF, 0x9393009300009393, 0x1919001900001919, 0x2121002100002121, +0x0E0E000E00000E0E, 0x4E4E004E00004E4E, 0x6565006500006565, 0xBDBD00BD0000BDBD, +0xB8B800B80000B8B8, 0x8F8F008F00008F8F, 0xEBEB00EB0000EBEB, 0xCECE00CE0000CECE, +0x3030003000003030, 0x5F5F005F00005F5F, 0xC5C500C50000C5C5, 0x1A1A001A00001A1A, +0xE1E100E10000E1E1, 0xCACA00CA0000CACA, 0x4747004700004747, 0x3D3D003D00003D3D, +0x0101000100000101, 0xD6D600D60000D6D6, 0x5656005600005656, 0x4D4D004D00004D4D, +0x0D0D000D00000D0D, 0x6666006600006666, 0xCCCC00CC0000CCCC, 0x2D2D002D00002D2D, +0x1212001200001212, 0x2020002000002020, 0xB1B100B10000B1B1, 0x9999009900009999, +0x4C4C004C00004C4C, 0xC2C200C20000C2C2, 0x7E7E007E00007E7E, 0x0505000500000505, +0xB7B700B70000B7B7, 0x3131003100003131, 0x1717001700001717, 0xD7D700D70000D7D7, +0x5858005800005858, 0x6161006100006161, 0x1B1B001B00001B1B, 0x1C1C001C00001C1C, +0x0F0F000F00000F0F, 0x1616001600001616, 0x1818001800001818, 0x2222002200002222, +0x4444004400004444, 0xB2B200B20000B2B2, 0xB5B500B50000B5B5, 0x9191009100009191, +0x0808000800000808, 0xA8A800A80000A8A8, 0xFCFC00FC0000FCFC, 0x5050005000005050, +0xD0D000D00000D0D0, 0x7D7D007D00007D7D, 0x8989008900008989, 0x9797009700009797, +0x5B5B005B00005B5B, 0x9595009500009595, 0xFFFF00FF0000FFFF, 0xD2D200D20000D2D2, +0xC4C400C40000C4C4, 0x4848004800004848, 0xF7F700F70000F7F7, 0xDBDB00DB0000DBDB, +0x0303000300000303, 0xDADA00DA0000DADA, 0x3F3F003F00003F3F, 0x9494009400009494, +0x5C5C005C00005C5C, 0x0202000200000202, 0x4A4A004A00004A4A, 0x3333003300003333, +0x6767006700006767, 0xF3F300F30000F3F3, 0x7F7F007F00007F7F, 0xE2E200E20000E2E2, +0x9B9B009B00009B9B, 0x2626002600002626, 0x3737003700003737, 0x3B3B003B00003B3B, +0x9696009600009696, 0x4B4B004B00004B4B, 0xBEBE00BE0000BEBE, 0x2E2E002E00002E2E, +0x7979007900007979, 0x8C8C008C00008C8C, 0x6E6E006E00006E6E, 0x8E8E008E00008E8E, +0xF5F500F50000F5F5, 0xB6B600B60000B6B6, 0xFDFD00FD0000FDFD, 0x5959005900005959, +0x9898009800009898, 0x6A6A006A00006A6A, 0x4646004600004646, 0xBABA00BA0000BABA, +0x2525002500002525, 0x4242004200004242, 0xA2A200A20000A2A2, 0xFAFA00FA0000FAFA, +0x0707000700000707, 0x5555005500005555, 0xEEEE00EE0000EEEE, 0x0A0A000A00000A0A, +0x4949004900004949, 0x6868006800006868, 0x3838003800003838, 0xA4A400A40000A4A4, +0x2828002800002828, 0x7B7B007B00007B7B, 0xC9C900C90000C9C9, 0xC1C100C10000C1C1, +0xE3E300E30000E3E3, 0xF4F400F40000F4F4, 0xC7C700C70000C7C7, 0x9E9E009E00009E9E }; + +const u64bit Camellia_SBOX5[256] = { +0x00E0E0E000E0E0E0, 0x0005050500050505, 0x0058585800585858, 0x00D9D9D900D9D9D9, +0x0067676700676767, 0x004E4E4E004E4E4E, 0x0081818100818181, 0x00CBCBCB00CBCBCB, +0x00C9C9C900C9C9C9, 0x000B0B0B000B0B0B, 0x00AEAEAE00AEAEAE, 0x006A6A6A006A6A6A, +0x00D5D5D500D5D5D5, 0x0018181800181818, 0x005D5D5D005D5D5D, 0x0082828200828282, +0x0046464600464646, 0x00DFDFDF00DFDFDF, 0x00D6D6D600D6D6D6, 0x0027272700272727, +0x008A8A8A008A8A8A, 0x0032323200323232, 0x004B4B4B004B4B4B, 0x0042424200424242, +0x00DBDBDB00DBDBDB, 0x001C1C1C001C1C1C, 0x009E9E9E009E9E9E, 0x009C9C9C009C9C9C, +0x003A3A3A003A3A3A, 0x00CACACA00CACACA, 0x0025252500252525, 0x007B7B7B007B7B7B, +0x000D0D0D000D0D0D, 0x0071717100717171, 0x005F5F5F005F5F5F, 0x001F1F1F001F1F1F, +0x00F8F8F800F8F8F8, 0x00D7D7D700D7D7D7, 0x003E3E3E003E3E3E, 0x009D9D9D009D9D9D, +0x007C7C7C007C7C7C, 0x0060606000606060, 0x00B9B9B900B9B9B9, 0x00BEBEBE00BEBEBE, +0x00BCBCBC00BCBCBC, 0x008B8B8B008B8B8B, 0x0016161600161616, 0x0034343400343434, +0x004D4D4D004D4D4D, 0x00C3C3C300C3C3C3, 0x0072727200727272, 0x0095959500959595, +0x00ABABAB00ABABAB, 0x008E8E8E008E8E8E, 0x00BABABA00BABABA, 0x007A7A7A007A7A7A, +0x00B3B3B300B3B3B3, 0x0002020200020202, 0x00B4B4B400B4B4B4, 0x00ADADAD00ADADAD, +0x00A2A2A200A2A2A2, 0x00ACACAC00ACACAC, 0x00D8D8D800D8D8D8, 0x009A9A9A009A9A9A, +0x0017171700171717, 0x001A1A1A001A1A1A, 0x0035353500353535, 0x00CCCCCC00CCCCCC, +0x00F7F7F700F7F7F7, 0x0099999900999999, 0x0061616100616161, 0x005A5A5A005A5A5A, +0x00E8E8E800E8E8E8, 0x0024242400242424, 0x0056565600565656, 0x0040404000404040, +0x00E1E1E100E1E1E1, 0x0063636300636363, 0x0009090900090909, 0x0033333300333333, +0x00BFBFBF00BFBFBF, 0x0098989800989898, 0x0097979700979797, 0x0085858500858585, +0x0068686800686868, 0x00FCFCFC00FCFCFC, 0x00ECECEC00ECECEC, 0x000A0A0A000A0A0A, +0x00DADADA00DADADA, 0x006F6F6F006F6F6F, 0x0053535300535353, 0x0062626200626262, +0x00A3A3A300A3A3A3, 0x002E2E2E002E2E2E, 0x0008080800080808, 0x00AFAFAF00AFAFAF, +0x0028282800282828, 0x00B0B0B000B0B0B0, 0x0074747400747474, 0x00C2C2C200C2C2C2, +0x00BDBDBD00BDBDBD, 0x0036363600363636, 0x0022222200222222, 0x0038383800383838, +0x0064646400646464, 0x001E1E1E001E1E1E, 0x0039393900393939, 0x002C2C2C002C2C2C, +0x00A6A6A600A6A6A6, 0x0030303000303030, 0x00E5E5E500E5E5E5, 0x0044444400444444, +0x00FDFDFD00FDFDFD, 0x0088888800888888, 0x009F9F9F009F9F9F, 0x0065656500656565, +0x0087878700878787, 0x006B6B6B006B6B6B, 0x00F4F4F400F4F4F4, 0x0023232300232323, +0x0048484800484848, 0x0010101000101010, 0x00D1D1D100D1D1D1, 0x0051515100515151, +0x00C0C0C000C0C0C0, 0x00F9F9F900F9F9F9, 0x00D2D2D200D2D2D2, 0x00A0A0A000A0A0A0, +0x0055555500555555, 0x00A1A1A100A1A1A1, 0x0041414100414141, 0x00FAFAFA00FAFAFA, +0x0043434300434343, 0x0013131300131313, 0x00C4C4C400C4C4C4, 0x002F2F2F002F2F2F, +0x00A8A8A800A8A8A8, 0x00B6B6B600B6B6B6, 0x003C3C3C003C3C3C, 0x002B2B2B002B2B2B, +0x00C1C1C100C1C1C1, 0x00FFFFFF00FFFFFF, 0x00C8C8C800C8C8C8, 0x00A5A5A500A5A5A5, +0x0020202000202020, 0x0089898900898989, 0x0000000000000000, 0x0090909000909090, +0x0047474700474747, 0x00EFEFEF00EFEFEF, 0x00EAEAEA00EAEAEA, 0x00B7B7B700B7B7B7, +0x0015151500151515, 0x0006060600060606, 0x00CDCDCD00CDCDCD, 0x00B5B5B500B5B5B5, +0x0012121200121212, 0x007E7E7E007E7E7E, 0x00BBBBBB00BBBBBB, 0x0029292900292929, +0x000F0F0F000F0F0F, 0x00B8B8B800B8B8B8, 0x0007070700070707, 0x0004040400040404, +0x009B9B9B009B9B9B, 0x0094949400949494, 0x0021212100212121, 0x0066666600666666, +0x00E6E6E600E6E6E6, 0x00CECECE00CECECE, 0x00EDEDED00EDEDED, 0x00E7E7E700E7E7E7, +0x003B3B3B003B3B3B, 0x00FEFEFE00FEFEFE, 0x007F7F7F007F7F7F, 0x00C5C5C500C5C5C5, +0x00A4A4A400A4A4A4, 0x0037373700373737, 0x00B1B1B100B1B1B1, 0x004C4C4C004C4C4C, +0x0091919100919191, 0x006E6E6E006E6E6E, 0x008D8D8D008D8D8D, 0x0076767600767676, +0x0003030300030303, 0x002D2D2D002D2D2D, 0x00DEDEDE00DEDEDE, 0x0096969600969696, +0x0026262600262626, 0x007D7D7D007D7D7D, 0x00C6C6C600C6C6C6, 0x005C5C5C005C5C5C, +0x00D3D3D300D3D3D3, 0x00F2F2F200F2F2F2, 0x004F4F4F004F4F4F, 0x0019191900191919, +0x003F3F3F003F3F3F, 0x00DCDCDC00DCDCDC, 0x0079797900797979, 0x001D1D1D001D1D1D, +0x0052525200525252, 0x00EBEBEB00EBEBEB, 0x00F3F3F300F3F3F3, 0x006D6D6D006D6D6D, +0x005E5E5E005E5E5E, 0x00FBFBFB00FBFBFB, 0x0069696900696969, 0x00B2B2B200B2B2B2, +0x00F0F0F000F0F0F0, 0x0031313100313131, 0x000C0C0C000C0C0C, 0x00D4D4D400D4D4D4, +0x00CFCFCF00CFCFCF, 0x008C8C8C008C8C8C, 0x00E2E2E200E2E2E2, 0x0075757500757575, +0x00A9A9A900A9A9A9, 0x004A4A4A004A4A4A, 0x0057575700575757, 0x0084848400848484, +0x0011111100111111, 0x0045454500454545, 0x001B1B1B001B1B1B, 0x00F5F5F500F5F5F5, +0x00E4E4E400E4E4E4, 0x000E0E0E000E0E0E, 0x0073737300737373, 0x00AAAAAA00AAAAAA, +0x00F1F1F100F1F1F1, 0x00DDDDDD00DDDDDD, 0x0059595900595959, 0x0014141400141414, +0x006C6C6C006C6C6C, 0x0092929200929292, 0x0054545400545454, 0x00D0D0D000D0D0D0, +0x0078787800787878, 0x0070707000707070, 0x00E3E3E300E3E3E3, 0x0049494900494949, +0x0080808000808080, 0x0050505000505050, 0x00A7A7A700A7A7A7, 0x00F6F6F600F6F6F6, +0x0077777700777777, 0x0093939300939393, 0x0086868600868686, 0x0083838300838383, +0x002A2A2A002A2A2A, 0x00C7C7C700C7C7C7, 0x005B5B5B005B5B5B, 0x00E9E9E900E9E9E9, +0x00EEEEEE00EEEEEE, 0x008F8F8F008F8F8F, 0x0001010100010101, 0x003D3D3D003D3D3D }; + +const u64bit Camellia_SBOX6[256] = { +0x3800383838003838, 0x4100414141004141, 0x1600161616001616, 0x7600767676007676, +0xD900D9D9D900D9D9, 0x9300939393009393, 0x6000606060006060, 0xF200F2F2F200F2F2, +0x7200727272007272, 0xC200C2C2C200C2C2, 0xAB00ABABAB00ABAB, 0x9A009A9A9A009A9A, +0x7500757575007575, 0x0600060606000606, 0x5700575757005757, 0xA000A0A0A000A0A0, +0x9100919191009191, 0xF700F7F7F700F7F7, 0xB500B5B5B500B5B5, 0xC900C9C9C900C9C9, +0xA200A2A2A200A2A2, 0x8C008C8C8C008C8C, 0xD200D2D2D200D2D2, 0x9000909090009090, +0xF600F6F6F600F6F6, 0x0700070707000707, 0xA700A7A7A700A7A7, 0x2700272727002727, +0x8E008E8E8E008E8E, 0xB200B2B2B200B2B2, 0x4900494949004949, 0xDE00DEDEDE00DEDE, +0x4300434343004343, 0x5C005C5C5C005C5C, 0xD700D7D7D700D7D7, 0xC700C7C7C700C7C7, +0x3E003E3E3E003E3E, 0xF500F5F5F500F5F5, 0x8F008F8F8F008F8F, 0x6700676767006767, +0x1F001F1F1F001F1F, 0x1800181818001818, 0x6E006E6E6E006E6E, 0xAF00AFAFAF00AFAF, +0x2F002F2F2F002F2F, 0xE200E2E2E200E2E2, 0x8500858585008585, 0x0D000D0D0D000D0D, +0x5300535353005353, 0xF000F0F0F000F0F0, 0x9C009C9C9C009C9C, 0x6500656565006565, +0xEA00EAEAEA00EAEA, 0xA300A3A3A300A3A3, 0xAE00AEAEAE00AEAE, 0x9E009E9E9E009E9E, +0xEC00ECECEC00ECEC, 0x8000808080008080, 0x2D002D2D2D002D2D, 0x6B006B6B6B006B6B, +0xA800A8A8A800A8A8, 0x2B002B2B2B002B2B, 0x3600363636003636, 0xA600A6A6A600A6A6, +0xC500C5C5C500C5C5, 0x8600868686008686, 0x4D004D4D4D004D4D, 0x3300333333003333, +0xFD00FDFDFD00FDFD, 0x6600666666006666, 0x5800585858005858, 0x9600969696009696, +0x3A003A3A3A003A3A, 0x0900090909000909, 0x9500959595009595, 0x1000101010001010, +0x7800787878007878, 0xD800D8D8D800D8D8, 0x4200424242004242, 0xCC00CCCCCC00CCCC, +0xEF00EFEFEF00EFEF, 0x2600262626002626, 0xE500E5E5E500E5E5, 0x6100616161006161, +0x1A001A1A1A001A1A, 0x3F003F3F3F003F3F, 0x3B003B3B3B003B3B, 0x8200828282008282, +0xB600B6B6B600B6B6, 0xDB00DBDBDB00DBDB, 0xD400D4D4D400D4D4, 0x9800989898009898, +0xE800E8E8E800E8E8, 0x8B008B8B8B008B8B, 0x0200020202000202, 0xEB00EBEBEB00EBEB, +0x0A000A0A0A000A0A, 0x2C002C2C2C002C2C, 0x1D001D1D1D001D1D, 0xB000B0B0B000B0B0, +0x6F006F6F6F006F6F, 0x8D008D8D8D008D8D, 0x8800888888008888, 0x0E000E0E0E000E0E, +0x1900191919001919, 0x8700878787008787, 0x4E004E4E4E004E4E, 0x0B000B0B0B000B0B, +0xA900A9A9A900A9A9, 0x0C000C0C0C000C0C, 0x7900797979007979, 0x1100111111001111, +0x7F007F7F7F007F7F, 0x2200222222002222, 0xE700E7E7E700E7E7, 0x5900595959005959, +0xE100E1E1E100E1E1, 0xDA00DADADA00DADA, 0x3D003D3D3D003D3D, 0xC800C8C8C800C8C8, +0x1200121212001212, 0x0400040404000404, 0x7400747474007474, 0x5400545454005454, +0x3000303030003030, 0x7E007E7E7E007E7E, 0xB400B4B4B400B4B4, 0x2800282828002828, +0x5500555555005555, 0x6800686868006868, 0x5000505050005050, 0xBE00BEBEBE00BEBE, +0xD000D0D0D000D0D0, 0xC400C4C4C400C4C4, 0x3100313131003131, 0xCB00CBCBCB00CBCB, +0x2A002A2A2A002A2A, 0xAD00ADADAD00ADAD, 0x0F000F0F0F000F0F, 0xCA00CACACA00CACA, +0x7000707070007070, 0xFF00FFFFFF00FFFF, 0x3200323232003232, 0x6900696969006969, +0x0800080808000808, 0x6200626262006262, 0x0000000000000000, 0x2400242424002424, +0xD100D1D1D100D1D1, 0xFB00FBFBFB00FBFB, 0xBA00BABABA00BABA, 0xED00EDEDED00EDED, +0x4500454545004545, 0x8100818181008181, 0x7300737373007373, 0x6D006D6D6D006D6D, +0x8400848484008484, 0x9F009F9F9F009F9F, 0xEE00EEEEEE00EEEE, 0x4A004A4A4A004A4A, +0xC300C3C3C300C3C3, 0x2E002E2E2E002E2E, 0xC100C1C1C100C1C1, 0x0100010101000101, +0xE600E6E6E600E6E6, 0x2500252525002525, 0x4800484848004848, 0x9900999999009999, +0xB900B9B9B900B9B9, 0xB300B3B3B300B3B3, 0x7B007B7B7B007B7B, 0xF900F9F9F900F9F9, +0xCE00CECECE00CECE, 0xBF00BFBFBF00BFBF, 0xDF00DFDFDF00DFDF, 0x7100717171007171, +0x2900292929002929, 0xCD00CDCDCD00CDCD, 0x6C006C6C6C006C6C, 0x1300131313001313, +0x6400646464006464, 0x9B009B9B9B009B9B, 0x6300636363006363, 0x9D009D9D9D009D9D, +0xC000C0C0C000C0C0, 0x4B004B4B4B004B4B, 0xB700B7B7B700B7B7, 0xA500A5A5A500A5A5, +0x8900898989008989, 0x5F005F5F5F005F5F, 0xB100B1B1B100B1B1, 0x1700171717001717, +0xF400F4F4F400F4F4, 0xBC00BCBCBC00BCBC, 0xD300D3D3D300D3D3, 0x4600464646004646, +0xCF00CFCFCF00CFCF, 0x3700373737003737, 0x5E005E5E5E005E5E, 0x4700474747004747, +0x9400949494009494, 0xFA00FAFAFA00FAFA, 0xFC00FCFCFC00FCFC, 0x5B005B5B5B005B5B, +0x9700979797009797, 0xFE00FEFEFE00FEFE, 0x5A005A5A5A005A5A, 0xAC00ACACAC00ACAC, +0x3C003C3C3C003C3C, 0x4C004C4C4C004C4C, 0x0300030303000303, 0x3500353535003535, +0xF300F3F3F300F3F3, 0x2300232323002323, 0xB800B8B8B800B8B8, 0x5D005D5D5D005D5D, +0x6A006A6A6A006A6A, 0x9200929292009292, 0xD500D5D5D500D5D5, 0x2100212121002121, +0x4400444444004444, 0x5100515151005151, 0xC600C6C6C600C6C6, 0x7D007D7D7D007D7D, +0x3900393939003939, 0x8300838383008383, 0xDC00DCDCDC00DCDC, 0xAA00AAAAAA00AAAA, +0x7C007C7C7C007C7C, 0x7700777777007777, 0x5600565656005656, 0x0500050505000505, +0x1B001B1B1B001B1B, 0xA400A4A4A400A4A4, 0x1500151515001515, 0x3400343434003434, +0x1E001E1E1E001E1E, 0x1C001C1C1C001C1C, 0xF800F8F8F800F8F8, 0x5200525252005252, +0x2000202020002020, 0x1400141414001414, 0xE900E9E9E900E9E9, 0xBD00BDBDBD00BDBD, +0xDD00DDDDDD00DDDD, 0xE400E4E4E400E4E4, 0xA100A1A1A100A1A1, 0xE000E0E0E000E0E0, +0x8A008A8A8A008A8A, 0xF100F1F1F100F1F1, 0xD600D6D6D600D6D6, 0x7A007A7A7A007A7A, +0xBB00BBBBBB00BBBB, 0xE300E3E3E300E3E3, 0x4000404040004040, 0x4F004F4F4F004F4F }; + +const u64bit Camellia_SBOX7[256] = { +0x7070007070700070, 0x2C2C002C2C2C002C, 0xB3B300B3B3B300B3, 0xC0C000C0C0C000C0, +0xE4E400E4E4E400E4, 0x5757005757570057, 0xEAEA00EAEAEA00EA, 0xAEAE00AEAEAE00AE, +0x2323002323230023, 0x6B6B006B6B6B006B, 0x4545004545450045, 0xA5A500A5A5A500A5, +0xEDED00EDEDED00ED, 0x4F4F004F4F4F004F, 0x1D1D001D1D1D001D, 0x9292009292920092, +0x8686008686860086, 0xAFAF00AFAFAF00AF, 0x7C7C007C7C7C007C, 0x1F1F001F1F1F001F, +0x3E3E003E3E3E003E, 0xDCDC00DCDCDC00DC, 0x5E5E005E5E5E005E, 0x0B0B000B0B0B000B, +0xA6A600A6A6A600A6, 0x3939003939390039, 0xD5D500D5D5D500D5, 0x5D5D005D5D5D005D, +0xD9D900D9D9D900D9, 0x5A5A005A5A5A005A, 0x5151005151510051, 0x6C6C006C6C6C006C, +0x8B8B008B8B8B008B, 0x9A9A009A9A9A009A, 0xFBFB00FBFBFB00FB, 0xB0B000B0B0B000B0, +0x7474007474740074, 0x2B2B002B2B2B002B, 0xF0F000F0F0F000F0, 0x8484008484840084, +0xDFDF00DFDFDF00DF, 0xCBCB00CBCBCB00CB, 0x3434003434340034, 0x7676007676760076, +0x6D6D006D6D6D006D, 0xA9A900A9A9A900A9, 0xD1D100D1D1D100D1, 0x0404000404040004, +0x1414001414140014, 0x3A3A003A3A3A003A, 0xDEDE00DEDEDE00DE, 0x1111001111110011, +0x3232003232320032, 0x9C9C009C9C9C009C, 0x5353005353530053, 0xF2F200F2F2F200F2, +0xFEFE00FEFEFE00FE, 0xCFCF00CFCFCF00CF, 0xC3C300C3C3C300C3, 0x7A7A007A7A7A007A, +0x2424002424240024, 0xE8E800E8E8E800E8, 0x6060006060600060, 0x6969006969690069, +0xAAAA00AAAAAA00AA, 0xA0A000A0A0A000A0, 0xA1A100A1A1A100A1, 0x6262006262620062, +0x5454005454540054, 0x1E1E001E1E1E001E, 0xE0E000E0E0E000E0, 0x6464006464640064, +0x1010001010100010, 0x0000000000000000, 0xA3A300A3A3A300A3, 0x7575007575750075, +0x8A8A008A8A8A008A, 0xE6E600E6E6E600E6, 0x0909000909090009, 0xDDDD00DDDDDD00DD, +0x8787008787870087, 0x8383008383830083, 0xCDCD00CDCDCD00CD, 0x9090009090900090, +0x7373007373730073, 0xF6F600F6F6F600F6, 0x9D9D009D9D9D009D, 0xBFBF00BFBFBF00BF, +0x5252005252520052, 0xD8D800D8D8D800D8, 0xC8C800C8C8C800C8, 0xC6C600C6C6C600C6, +0x8181008181810081, 0x6F6F006F6F6F006F, 0x1313001313130013, 0x6363006363630063, +0xE9E900E9E9E900E9, 0xA7A700A7A7A700A7, 0x9F9F009F9F9F009F, 0xBCBC00BCBCBC00BC, +0x2929002929290029, 0xF9F900F9F9F900F9, 0x2F2F002F2F2F002F, 0xB4B400B4B4B400B4, +0x7878007878780078, 0x0606000606060006, 0xE7E700E7E7E700E7, 0x7171007171710071, +0xD4D400D4D4D400D4, 0xABAB00ABABAB00AB, 0x8888008888880088, 0x8D8D008D8D8D008D, +0x7272007272720072, 0xB9B900B9B9B900B9, 0xF8F800F8F8F800F8, 0xACAC00ACACAC00AC, +0x3636003636360036, 0x2A2A002A2A2A002A, 0x3C3C003C3C3C003C, 0xF1F100F1F1F100F1, +0x4040004040400040, 0xD3D300D3D3D300D3, 0xBBBB00BBBBBB00BB, 0x4343004343430043, +0x1515001515150015, 0xADAD00ADADAD00AD, 0x7777007777770077, 0x8080008080800080, +0x8282008282820082, 0xECEC00ECECEC00EC, 0x2727002727270027, 0xE5E500E5E5E500E5, +0x8585008585850085, 0x3535003535350035, 0x0C0C000C0C0C000C, 0x4141004141410041, +0xEFEF00EFEFEF00EF, 0x9393009393930093, 0x1919001919190019, 0x2121002121210021, +0x0E0E000E0E0E000E, 0x4E4E004E4E4E004E, 0x6565006565650065, 0xBDBD00BDBDBD00BD, +0xB8B800B8B8B800B8, 0x8F8F008F8F8F008F, 0xEBEB00EBEBEB00EB, 0xCECE00CECECE00CE, +0x3030003030300030, 0x5F5F005F5F5F005F, 0xC5C500C5C5C500C5, 0x1A1A001A1A1A001A, +0xE1E100E1E1E100E1, 0xCACA00CACACA00CA, 0x4747004747470047, 0x3D3D003D3D3D003D, +0x0101000101010001, 0xD6D600D6D6D600D6, 0x5656005656560056, 0x4D4D004D4D4D004D, +0x0D0D000D0D0D000D, 0x6666006666660066, 0xCCCC00CCCCCC00CC, 0x2D2D002D2D2D002D, +0x1212001212120012, 0x2020002020200020, 0xB1B100B1B1B100B1, 0x9999009999990099, +0x4C4C004C4C4C004C, 0xC2C200C2C2C200C2, 0x7E7E007E7E7E007E, 0x0505000505050005, +0xB7B700B7B7B700B7, 0x3131003131310031, 0x1717001717170017, 0xD7D700D7D7D700D7, +0x5858005858580058, 0x6161006161610061, 0x1B1B001B1B1B001B, 0x1C1C001C1C1C001C, +0x0F0F000F0F0F000F, 0x1616001616160016, 0x1818001818180018, 0x2222002222220022, +0x4444004444440044, 0xB2B200B2B2B200B2, 0xB5B500B5B5B500B5, 0x9191009191910091, +0x0808000808080008, 0xA8A800A8A8A800A8, 0xFCFC00FCFCFC00FC, 0x5050005050500050, +0xD0D000D0D0D000D0, 0x7D7D007D7D7D007D, 0x8989008989890089, 0x9797009797970097, +0x5B5B005B5B5B005B, 0x9595009595950095, 0xFFFF00FFFFFF00FF, 0xD2D200D2D2D200D2, +0xC4C400C4C4C400C4, 0x4848004848480048, 0xF7F700F7F7F700F7, 0xDBDB00DBDBDB00DB, +0x0303000303030003, 0xDADA00DADADA00DA, 0x3F3F003F3F3F003F, 0x9494009494940094, +0x5C5C005C5C5C005C, 0x0202000202020002, 0x4A4A004A4A4A004A, 0x3333003333330033, +0x6767006767670067, 0xF3F300F3F3F300F3, 0x7F7F007F7F7F007F, 0xE2E200E2E2E200E2, +0x9B9B009B9B9B009B, 0x2626002626260026, 0x3737003737370037, 0x3B3B003B3B3B003B, +0x9696009696960096, 0x4B4B004B4B4B004B, 0xBEBE00BEBEBE00BE, 0x2E2E002E2E2E002E, +0x7979007979790079, 0x8C8C008C8C8C008C, 0x6E6E006E6E6E006E, 0x8E8E008E8E8E008E, +0xF5F500F5F5F500F5, 0xB6B600B6B6B600B6, 0xFDFD00FDFDFD00FD, 0x5959005959590059, +0x9898009898980098, 0x6A6A006A6A6A006A, 0x4646004646460046, 0xBABA00BABABA00BA, +0x2525002525250025, 0x4242004242420042, 0xA2A200A2A2A200A2, 0xFAFA00FAFAFA00FA, +0x0707000707070007, 0x5555005555550055, 0xEEEE00EEEEEE00EE, 0x0A0A000A0A0A000A, +0x4949004949490049, 0x6868006868680068, 0x3838003838380038, 0xA4A400A4A4A400A4, +0x2828002828280028, 0x7B7B007B7B7B007B, 0xC9C900C9C9C900C9, 0xC1C100C1C1C100C1, +0xE3E300E3E3E300E3, 0xF4F400F4F4F400F4, 0xC7C700C7C7C700C7, 0x9E9E009E9E9E009E }; + +const u64bit Camellia_SBOX8[256] = { +0x7070700070707000, 0x8282820082828200, 0x2C2C2C002C2C2C00, 0xECECEC00ECECEC00, +0xB3B3B300B3B3B300, 0x2727270027272700, 0xC0C0C000C0C0C000, 0xE5E5E500E5E5E500, +0xE4E4E400E4E4E400, 0x8585850085858500, 0x5757570057575700, 0x3535350035353500, +0xEAEAEA00EAEAEA00, 0x0C0C0C000C0C0C00, 0xAEAEAE00AEAEAE00, 0x4141410041414100, +0x2323230023232300, 0xEFEFEF00EFEFEF00, 0x6B6B6B006B6B6B00, 0x9393930093939300, +0x4545450045454500, 0x1919190019191900, 0xA5A5A500A5A5A500, 0x2121210021212100, +0xEDEDED00EDEDED00, 0x0E0E0E000E0E0E00, 0x4F4F4F004F4F4F00, 0x4E4E4E004E4E4E00, +0x1D1D1D001D1D1D00, 0x6565650065656500, 0x9292920092929200, 0xBDBDBD00BDBDBD00, +0x8686860086868600, 0xB8B8B800B8B8B800, 0xAFAFAF00AFAFAF00, 0x8F8F8F008F8F8F00, +0x7C7C7C007C7C7C00, 0xEBEBEB00EBEBEB00, 0x1F1F1F001F1F1F00, 0xCECECE00CECECE00, +0x3E3E3E003E3E3E00, 0x3030300030303000, 0xDCDCDC00DCDCDC00, 0x5F5F5F005F5F5F00, +0x5E5E5E005E5E5E00, 0xC5C5C500C5C5C500, 0x0B0B0B000B0B0B00, 0x1A1A1A001A1A1A00, +0xA6A6A600A6A6A600, 0xE1E1E100E1E1E100, 0x3939390039393900, 0xCACACA00CACACA00, +0xD5D5D500D5D5D500, 0x4747470047474700, 0x5D5D5D005D5D5D00, 0x3D3D3D003D3D3D00, +0xD9D9D900D9D9D900, 0x0101010001010100, 0x5A5A5A005A5A5A00, 0xD6D6D600D6D6D600, +0x5151510051515100, 0x5656560056565600, 0x6C6C6C006C6C6C00, 0x4D4D4D004D4D4D00, +0x8B8B8B008B8B8B00, 0x0D0D0D000D0D0D00, 0x9A9A9A009A9A9A00, 0x6666660066666600, +0xFBFBFB00FBFBFB00, 0xCCCCCC00CCCCCC00, 0xB0B0B000B0B0B000, 0x2D2D2D002D2D2D00, +0x7474740074747400, 0x1212120012121200, 0x2B2B2B002B2B2B00, 0x2020200020202000, +0xF0F0F000F0F0F000, 0xB1B1B100B1B1B100, 0x8484840084848400, 0x9999990099999900, +0xDFDFDF00DFDFDF00, 0x4C4C4C004C4C4C00, 0xCBCBCB00CBCBCB00, 0xC2C2C200C2C2C200, +0x3434340034343400, 0x7E7E7E007E7E7E00, 0x7676760076767600, 0x0505050005050500, +0x6D6D6D006D6D6D00, 0xB7B7B700B7B7B700, 0xA9A9A900A9A9A900, 0x3131310031313100, +0xD1D1D100D1D1D100, 0x1717170017171700, 0x0404040004040400, 0xD7D7D700D7D7D700, +0x1414140014141400, 0x5858580058585800, 0x3A3A3A003A3A3A00, 0x6161610061616100, +0xDEDEDE00DEDEDE00, 0x1B1B1B001B1B1B00, 0x1111110011111100, 0x1C1C1C001C1C1C00, +0x3232320032323200, 0x0F0F0F000F0F0F00, 0x9C9C9C009C9C9C00, 0x1616160016161600, +0x5353530053535300, 0x1818180018181800, 0xF2F2F200F2F2F200, 0x2222220022222200, +0xFEFEFE00FEFEFE00, 0x4444440044444400, 0xCFCFCF00CFCFCF00, 0xB2B2B200B2B2B200, +0xC3C3C300C3C3C300, 0xB5B5B500B5B5B500, 0x7A7A7A007A7A7A00, 0x9191910091919100, +0x2424240024242400, 0x0808080008080800, 0xE8E8E800E8E8E800, 0xA8A8A800A8A8A800, +0x6060600060606000, 0xFCFCFC00FCFCFC00, 0x6969690069696900, 0x5050500050505000, +0xAAAAAA00AAAAAA00, 0xD0D0D000D0D0D000, 0xA0A0A000A0A0A000, 0x7D7D7D007D7D7D00, +0xA1A1A100A1A1A100, 0x8989890089898900, 0x6262620062626200, 0x9797970097979700, +0x5454540054545400, 0x5B5B5B005B5B5B00, 0x1E1E1E001E1E1E00, 0x9595950095959500, +0xE0E0E000E0E0E000, 0xFFFFFF00FFFFFF00, 0x6464640064646400, 0xD2D2D200D2D2D200, +0x1010100010101000, 0xC4C4C400C4C4C400, 0x0000000000000000, 0x4848480048484800, +0xA3A3A300A3A3A300, 0xF7F7F700F7F7F700, 0x7575750075757500, 0xDBDBDB00DBDBDB00, +0x8A8A8A008A8A8A00, 0x0303030003030300, 0xE6E6E600E6E6E600, 0xDADADA00DADADA00, +0x0909090009090900, 0x3F3F3F003F3F3F00, 0xDDDDDD00DDDDDD00, 0x9494940094949400, +0x8787870087878700, 0x5C5C5C005C5C5C00, 0x8383830083838300, 0x0202020002020200, +0xCDCDCD00CDCDCD00, 0x4A4A4A004A4A4A00, 0x9090900090909000, 0x3333330033333300, +0x7373730073737300, 0x6767670067676700, 0xF6F6F600F6F6F600, 0xF3F3F300F3F3F300, +0x9D9D9D009D9D9D00, 0x7F7F7F007F7F7F00, 0xBFBFBF00BFBFBF00, 0xE2E2E200E2E2E200, +0x5252520052525200, 0x9B9B9B009B9B9B00, 0xD8D8D800D8D8D800, 0x2626260026262600, +0xC8C8C800C8C8C800, 0x3737370037373700, 0xC6C6C600C6C6C600, 0x3B3B3B003B3B3B00, +0x8181810081818100, 0x9696960096969600, 0x6F6F6F006F6F6F00, 0x4B4B4B004B4B4B00, +0x1313130013131300, 0xBEBEBE00BEBEBE00, 0x6363630063636300, 0x2E2E2E002E2E2E00, +0xE9E9E900E9E9E900, 0x7979790079797900, 0xA7A7A700A7A7A700, 0x8C8C8C008C8C8C00, +0x9F9F9F009F9F9F00, 0x6E6E6E006E6E6E00, 0xBCBCBC00BCBCBC00, 0x8E8E8E008E8E8E00, +0x2929290029292900, 0xF5F5F500F5F5F500, 0xF9F9F900F9F9F900, 0xB6B6B600B6B6B600, +0x2F2F2F002F2F2F00, 0xFDFDFD00FDFDFD00, 0xB4B4B400B4B4B400, 0x5959590059595900, +0x7878780078787800, 0x9898980098989800, 0x0606060006060600, 0x6A6A6A006A6A6A00, +0xE7E7E700E7E7E700, 0x4646460046464600, 0x7171710071717100, 0xBABABA00BABABA00, +0xD4D4D400D4D4D400, 0x2525250025252500, 0xABABAB00ABABAB00, 0x4242420042424200, +0x8888880088888800, 0xA2A2A200A2A2A200, 0x8D8D8D008D8D8D00, 0xFAFAFA00FAFAFA00, +0x7272720072727200, 0x0707070007070700, 0xB9B9B900B9B9B900, 0x5555550055555500, +0xF8F8F800F8F8F800, 0xEEEEEE00EEEEEE00, 0xACACAC00ACACAC00, 0x0A0A0A000A0A0A00, +0x3636360036363600, 0x4949490049494900, 0x2A2A2A002A2A2A00, 0x6868680068686800, +0x3C3C3C003C3C3C00, 0x3838380038383800, 0xF1F1F100F1F1F100, 0xA4A4A400A4A4A400, +0x4040400040404000, 0x2828280028282800, 0xD3D3D300D3D3D300, 0x7B7B7B007B7B7B00, +0xBBBBBB00BBBBBB00, 0xC9C9C900C9C9C900, 0x4343430043434300, 0xC1C1C100C1C1C100, +0x1515150015151500, 0xE3E3E300E3E3E300, 0xADADAD00ADADAD00, 0xF4F4F400F4F4F400, +0x7777770077777700, 0xC7C7C700C7C7C700, 0x8080800080808000, 0x9E9E9E009E9E9E00 }; + +} + +#endif diff --git a/src/lib/block/camellia/info.txt b/src/lib/block/camellia/info.txt new file mode 100644 index 000000000..2bcfe80d0 --- /dev/null +++ b/src/lib/block/camellia/info.txt @@ -0,0 +1,9 @@ +define CAMELLIA 20131128 + + +camellia_sbox.h + + + +camellia.h + diff --git a/src/lib/block/cascade/cascade.cpp b/src/lib/block/cascade/cascade.cpp new file mode 100644 index 000000000..f1b1a8f2c --- /dev/null +++ b/src/lib/block/cascade/cascade.cpp @@ -0,0 +1,98 @@ +/* +* Block Cipher Cascade +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +void Cascade_Cipher::encrypt_n(const byte in[], byte out[], + size_t blocks) const + { + size_t c1_blocks = blocks * (block_size() / cipher1->block_size()); + size_t c2_blocks = blocks * (block_size() / cipher2->block_size()); + + cipher1->encrypt_n(in, out, c1_blocks); + cipher2->encrypt_n(out, out, c2_blocks); + } + +void Cascade_Cipher::decrypt_n(const byte in[], byte out[], + size_t blocks) const + { + size_t c1_blocks = blocks * (block_size() / cipher1->block_size()); + size_t c2_blocks = blocks * (block_size() / cipher2->block_size()); + + cipher2->decrypt_n(in, out, c2_blocks); + cipher1->decrypt_n(out, out, c1_blocks); + } + +void Cascade_Cipher::key_schedule(const byte key[], size_t) + { + const byte* key2 = key + cipher1->maximum_keylength(); + + cipher1->set_key(key , cipher1->maximum_keylength()); + cipher2->set_key(key2, cipher2->maximum_keylength()); + } + +void Cascade_Cipher::clear() + { + cipher1->clear(); + cipher2->clear(); + } + +std::string Cascade_Cipher::name() const + { + return "Cascade(" + cipher1->name() + "," + cipher2->name() + ")"; + } + +BlockCipher* Cascade_Cipher::clone() const + { + return new Cascade_Cipher(cipher1->clone(), + cipher2->clone()); + } + +namespace { + +size_t euclids_algorithm(size_t a, size_t b) + { + while(b != 0) // gcd + { + size_t t = b; + b = a % b; + a = t; + } + + return a; + } + +size_t block_size_for_cascade(size_t bs, size_t bs2) + { + if(bs == bs2) + return bs; + + size_t gcd = euclids_algorithm(bs, bs2); + + return (bs * bs2) / gcd; + } + +} + +Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) : + cipher1(c1), cipher2(c2) + { + block = block_size_for_cascade(c1->block_size(), c2->block_size()); + + if(block_size() % c1->block_size() || block_size() % c2->block_size()) + throw Internal_Error("Failure in " + name() + " constructor"); + } + +Cascade_Cipher::~Cascade_Cipher() + { + delete cipher1; + delete cipher2; + } + +} diff --git a/src/lib/block/cascade/cascade.h b/src/lib/block/cascade/cascade.h new file mode 100644 index 000000000..9b7d44fdf --- /dev/null +++ b/src/lib/block/cascade/cascade.h @@ -0,0 +1,58 @@ +/* +* Block Cipher Cascade +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CASCADE_H__ +#define BOTAN_CASCADE_H__ + +#include + +namespace Botan { + +/** +* Block Cipher Cascade +*/ +class BOTAN_DLL Cascade_Cipher : public BlockCipher + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + size_t block_size() const { return block; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(cipher1->maximum_keylength() + + cipher2->maximum_keylength()); + } + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * Create a cascade of two block ciphers + * @param cipher1 the first cipher + * @param cipher2 the second cipher + */ + Cascade_Cipher(BlockCipher* cipher1, BlockCipher* cipher2); + + Cascade_Cipher(const Cascade_Cipher&) = delete; + Cascade_Cipher& operator=(const Cascade_Cipher&) = delete; + + ~Cascade_Cipher(); + private: + void key_schedule(const byte[], size_t); + + size_t block; + BlockCipher* cipher1; + BlockCipher* cipher2; + }; + + +} + +#endif diff --git a/src/lib/block/cascade/info.txt b/src/lib/block/cascade/info.txt new file mode 100644 index 000000000..445e49086 --- /dev/null +++ b/src/lib/block/cascade/info.txt @@ -0,0 +1,9 @@ +define CASCADE 20131128 + + +cascade.h + + + +cascade.cpp + diff --git a/src/lib/block/cast/cast128.cpp b/src/lib/block/cast/cast128.cpp new file mode 100644 index 000000000..169b18f01 --- /dev/null +++ b/src/lib/block/cast/cast128.cpp @@ -0,0 +1,376 @@ +/* +* CAST-128 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* CAST-128 Round Type 1 +*/ +inline void R1(u32bit& L, u32bit R, u32bit MK, byte RK) + { + u32bit T = rotate_left(MK + R, RK); + L ^= (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) - + CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-128 Round Type 2 +*/ +inline void R2(u32bit& L, u32bit R, u32bit MK, byte RK) + { + u32bit T = rotate_left(MK ^ R, RK); + L ^= (CAST_SBOX1[get_byte(0, T)] - CAST_SBOX2[get_byte(1, T)] + + CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-128 Round Type 3 +*/ +inline void R3(u32bit& L, u32bit R, u32bit MK, byte RK) + { + u32bit T = rotate_left(MK - R, RK); + L ^= ((CAST_SBOX1[get_byte(0, T)] + CAST_SBOX2[get_byte(1, T)]) ^ + CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)]; + } + +} + +/* +* CAST-128 Encryption +*/ +void CAST_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + R1(L, R, MK[ 0], RK[ 0]); + R2(R, L, MK[ 1], RK[ 1]); + R3(L, R, MK[ 2], RK[ 2]); + R1(R, L, MK[ 3], RK[ 3]); + R2(L, R, MK[ 4], RK[ 4]); + R3(R, L, MK[ 5], RK[ 5]); + R1(L, R, MK[ 6], RK[ 6]); + R2(R, L, MK[ 7], RK[ 7]); + R3(L, R, MK[ 8], RK[ 8]); + R1(R, L, MK[ 9], RK[ 9]); + R2(L, R, MK[10], RK[10]); + R3(R, L, MK[11], RK[11]); + R1(L, R, MK[12], RK[12]); + R2(R, L, MK[13], RK[13]); + R3(L, R, MK[14], RK[14]); + R1(R, L, MK[15], RK[15]); + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-128 Decryption +*/ +void CAST_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + R1(L, R, MK[15], RK[15]); + R3(R, L, MK[14], RK[14]); + R2(L, R, MK[13], RK[13]); + R1(R, L, MK[12], RK[12]); + R3(L, R, MK[11], RK[11]); + R2(R, L, MK[10], RK[10]); + R1(L, R, MK[ 9], RK[ 9]); + R3(R, L, MK[ 8], RK[ 8]); + R2(L, R, MK[ 7], RK[ 7]); + R1(R, L, MK[ 6], RK[ 6]); + R3(L, R, MK[ 5], RK[ 5]); + R2(R, L, MK[ 4], RK[ 4]); + R1(L, R, MK[ 3], RK[ 3]); + R3(R, L, MK[ 2], RK[ 2]); + R2(L, R, MK[ 1], RK[ 1]); + R1(R, L, MK[ 0], RK[ 0]); + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-128 Key Schedule +*/ +void CAST_128::key_schedule(const byte key[], size_t length) + { + MK.resize(48); + RK.resize(48); + + secure_vector X(4); + for(size_t i = 0; i != length; ++i) + X[i/4] = (X[i/4] << 8) + key[i]; + + cast_ks(MK, X); + + secure_vector RK32(48); + cast_ks(RK32, X); + + for(size_t i = 0; i != 16; ++i) + RK[i] = RK32[i] % 32; + } + +void CAST_128::clear() + { + zap(MK); + zap(RK); + } + +/* +* S-Box Based Key Expansion +*/ +void CAST_128::cast_ks(secure_vector& K, + secure_vector& X) + { + static const u32bit S5[256] = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, + 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, + 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, + 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, + 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, + 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, + 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, + 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, + 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, + 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, + 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, + 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, + 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, + 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, + 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, + 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, + 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, + 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, + 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, + 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, + 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, + 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; + + static const u32bit S6[256] = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, + 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, + 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, + 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, + 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, + 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, + 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, + 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, + 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, + 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, + 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, + 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, + 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, + 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, + 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, + 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, + 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, + 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, + 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, + 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, + 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, + 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; + + static const u32bit S7[256] = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, + 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, + 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, + 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, + 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, + 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, + 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, + 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, + 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, + 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, + 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, + 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, + 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, + 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, + 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, + 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, + 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, + 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, + 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, + 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, + 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, + 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; + + static const u32bit S8[256] = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, + 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, + 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, + 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, + 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, + 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, + 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, + 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, + 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, + 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, + 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, + 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, + 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, + 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, + 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, + 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, + 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, + 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, + 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, + 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, + 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, + 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; + + class ByteReader + { + public: + byte operator()(size_t i) { return (X[i/4] >> (8*(3 - (i%4)))); } + ByteReader(const u32bit* x) : X(x) {} + private: + const u32bit* X; + }; + + secure_vector Z(4); + ByteReader x(&X[0]), z(&Z[0]); + + Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; + Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; + Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; + Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; + K[ 0] = S5[z( 8)] ^ S6[z( 9)] ^ S7[z( 7)] ^ S8[z( 6)] ^ S5[z( 2)]; + K[ 1] = S5[z(10)] ^ S6[z(11)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S6[z( 6)]; + K[ 2] = S5[z(12)] ^ S6[z(13)] ^ S7[z( 3)] ^ S8[z( 2)] ^ S7[z( 9)]; + K[ 3] = S5[z(14)] ^ S6[z(15)] ^ S7[z( 1)] ^ S8[z( 0)] ^ S8[z(12)]; + X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; + X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; + X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; + X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; + K[ 4] = S5[x( 3)] ^ S6[x( 2)] ^ S7[x(12)] ^ S8[x(13)] ^ S5[x( 8)]; + K[ 5] = S5[x( 1)] ^ S6[x( 0)] ^ S7[x(14)] ^ S8[x(15)] ^ S6[x(13)]; + K[ 6] = S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 8)] ^ S8[x( 9)] ^ S7[x( 3)]; + K[ 7] = S5[x( 5)] ^ S6[x( 4)] ^ S7[x(10)] ^ S8[x(11)] ^ S8[x( 7)]; + Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; + Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; + Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; + Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; + K[ 8] = S5[z( 3)] ^ S6[z( 2)] ^ S7[z(12)] ^ S8[z(13)] ^ S5[z( 9)]; + K[ 9] = S5[z( 1)] ^ S6[z( 0)] ^ S7[z(14)] ^ S8[z(15)] ^ S6[z(12)]; + K[10] = S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 8)] ^ S8[z( 9)] ^ S7[z( 2)]; + K[11] = S5[z( 5)] ^ S6[z( 4)] ^ S7[z(10)] ^ S8[z(11)] ^ S8[z( 6)]; + X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; + X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; + X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; + X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; + K[12] = S5[x( 8)] ^ S6[x( 9)] ^ S7[x( 7)] ^ S8[x( 6)] ^ S5[x( 3)]; + K[13] = S5[x(10)] ^ S6[x(11)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S6[x( 7)]; + K[14] = S5[x(12)] ^ S6[x(13)] ^ S7[x( 3)] ^ S8[x( 2)] ^ S7[x( 8)]; + K[15] = S5[x(14)] ^ S6[x(15)] ^ S7[x( 1)] ^ S8[x( 0)] ^ S8[x(13)]; + } + +} diff --git a/src/lib/block/cast/cast128.h b/src/lib/block/cast/cast128.h new file mode 100644 index 000000000..233c1e478 --- /dev/null +++ b/src/lib/block/cast/cast128.h @@ -0,0 +1,40 @@ +/* +* CAST-128 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CAST128_H__ +#define BOTAN_CAST128_H__ + +#include + +namespace Botan { + +/** +* CAST-128 +*/ +class BOTAN_DLL CAST_128 : public Block_Cipher_Fixed_Params<8, 11, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "CAST-128"; } + BlockCipher* clone() const { return new CAST_128; } + + private: + void key_schedule(const byte[], size_t); + + static void cast_ks(secure_vector& ks, + secure_vector& user_key); + + secure_vector MK; + secure_vector RK; + }; + +} + +#endif diff --git a/src/lib/block/cast/cast256.cpp b/src/lib/block/cast/cast256.cpp new file mode 100644 index 000000000..0c4dbb941 --- /dev/null +++ b/src/lib/block/cast/cast256.cpp @@ -0,0 +1,228 @@ +/* +* CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* CAST-256 Round Type 1 +*/ +void round1(u32bit& out, u32bit in, u32bit mask, u32bit rot) + { + u32bit temp = rotate_left(mask + in, rot); + out ^= (CAST_SBOX1[get_byte(0, temp)] ^ CAST_SBOX2[get_byte(1, temp)]) - + CAST_SBOX3[get_byte(2, temp)] + CAST_SBOX4[get_byte(3, temp)]; + } + +/* +* CAST-256 Round Type 2 +*/ +void round2(u32bit& out, u32bit in, u32bit mask, u32bit rot) + { + u32bit temp = rotate_left(mask ^ in, rot); + out ^= (CAST_SBOX1[get_byte(0, temp)] - CAST_SBOX2[get_byte(1, temp)] + + CAST_SBOX3[get_byte(2, temp)]) ^ CAST_SBOX4[get_byte(3, temp)]; + } + +/* +* CAST-256 Round Type 3 +*/ +void round3(u32bit& out, u32bit in, u32bit mask, u32bit rot) + { + u32bit temp = rotate_left(mask - in, rot); + out ^= ((CAST_SBOX1[get_byte(0, temp)] + CAST_SBOX2[get_byte(1, temp)]) ^ + CAST_SBOX3[get_byte(2, temp)]) - CAST_SBOX4[get_byte(3, temp)]; + } + +} + +/* +* CAST-256 Encryption +*/ +void CAST_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_be(in, 0); + u32bit B = load_be(in, 1); + u32bit C = load_be(in, 2); + u32bit D = load_be(in, 3); + + round1(C, D, MK[ 0], RK[ 0]); round2(B, C, MK[ 1], RK[ 1]); + round3(A, B, MK[ 2], RK[ 2]); round1(D, A, MK[ 3], RK[ 3]); + round1(C, D, MK[ 4], RK[ 4]); round2(B, C, MK[ 5], RK[ 5]); + round3(A, B, MK[ 6], RK[ 6]); round1(D, A, MK[ 7], RK[ 7]); + round1(C, D, MK[ 8], RK[ 8]); round2(B, C, MK[ 9], RK[ 9]); + round3(A, B, MK[10], RK[10]); round1(D, A, MK[11], RK[11]); + round1(C, D, MK[12], RK[12]); round2(B, C, MK[13], RK[13]); + round3(A, B, MK[14], RK[14]); round1(D, A, MK[15], RK[15]); + round1(C, D, MK[16], RK[16]); round2(B, C, MK[17], RK[17]); + round3(A, B, MK[18], RK[18]); round1(D, A, MK[19], RK[19]); + round1(C, D, MK[20], RK[20]); round2(B, C, MK[21], RK[21]); + round3(A, B, MK[22], RK[22]); round1(D, A, MK[23], RK[23]); + round1(D, A, MK[27], RK[27]); round3(A, B, MK[26], RK[26]); + round2(B, C, MK[25], RK[25]); round1(C, D, MK[24], RK[24]); + round1(D, A, MK[31], RK[31]); round3(A, B, MK[30], RK[30]); + round2(B, C, MK[29], RK[29]); round1(C, D, MK[28], RK[28]); + round1(D, A, MK[35], RK[35]); round3(A, B, MK[34], RK[34]); + round2(B, C, MK[33], RK[33]); round1(C, D, MK[32], RK[32]); + round1(D, A, MK[39], RK[39]); round3(A, B, MK[38], RK[38]); + round2(B, C, MK[37], RK[37]); round1(C, D, MK[36], RK[36]); + round1(D, A, MK[43], RK[43]); round3(A, B, MK[42], RK[42]); + round2(B, C, MK[41], RK[41]); round1(C, D, MK[40], RK[40]); + round1(D, A, MK[47], RK[47]); round3(A, B, MK[46], RK[46]); + round2(B, C, MK[45], RK[45]); round1(C, D, MK[44], RK[44]); + + store_be(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-256 Decryption +*/ +void CAST_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_be(in, 0); + u32bit B = load_be(in, 1); + u32bit C = load_be(in, 2); + u32bit D = load_be(in, 3); + + round1(C, D, MK[44], RK[44]); round2(B, C, MK[45], RK[45]); + round3(A, B, MK[46], RK[46]); round1(D, A, MK[47], RK[47]); + round1(C, D, MK[40], RK[40]); round2(B, C, MK[41], RK[41]); + round3(A, B, MK[42], RK[42]); round1(D, A, MK[43], RK[43]); + round1(C, D, MK[36], RK[36]); round2(B, C, MK[37], RK[37]); + round3(A, B, MK[38], RK[38]); round1(D, A, MK[39], RK[39]); + round1(C, D, MK[32], RK[32]); round2(B, C, MK[33], RK[33]); + round3(A, B, MK[34], RK[34]); round1(D, A, MK[35], RK[35]); + round1(C, D, MK[28], RK[28]); round2(B, C, MK[29], RK[29]); + round3(A, B, MK[30], RK[30]); round1(D, A, MK[31], RK[31]); + round1(C, D, MK[24], RK[24]); round2(B, C, MK[25], RK[25]); + round3(A, B, MK[26], RK[26]); round1(D, A, MK[27], RK[27]); + round1(D, A, MK[23], RK[23]); round3(A, B, MK[22], RK[22]); + round2(B, C, MK[21], RK[21]); round1(C, D, MK[20], RK[20]); + round1(D, A, MK[19], RK[19]); round3(A, B, MK[18], RK[18]); + round2(B, C, MK[17], RK[17]); round1(C, D, MK[16], RK[16]); + round1(D, A, MK[15], RK[15]); round3(A, B, MK[14], RK[14]); + round2(B, C, MK[13], RK[13]); round1(C, D, MK[12], RK[12]); + round1(D, A, MK[11], RK[11]); round3(A, B, MK[10], RK[10]); + round2(B, C, MK[ 9], RK[ 9]); round1(C, D, MK[ 8], RK[ 8]); + round1(D, A, MK[ 7], RK[ 7]); round3(A, B, MK[ 6], RK[ 6]); + round2(B, C, MK[ 5], RK[ 5]); round1(C, D, MK[ 4], RK[ 4]); + round1(D, A, MK[ 3], RK[ 3]); round3(A, B, MK[ 2], RK[ 2]); + round2(B, C, MK[ 1], RK[ 1]); round1(C, D, MK[ 0], RK[ 0]); + + store_be(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-256 Key Schedule +*/ +void CAST_256::key_schedule(const byte key[], size_t length) + { + static const u32bit KEY_MASK[192] = { + 0x5A827999, 0xC95C653A, 0x383650DB, 0xA7103C7C, 0x15EA281D, 0x84C413BE, + 0xF39DFF5F, 0x6277EB00, 0xD151D6A1, 0x402BC242, 0xAF05ADE3, 0x1DDF9984, + 0x8CB98525, 0xFB9370C6, 0x6A6D5C67, 0xD9474808, 0x482133A9, 0xB6FB1F4A, + 0x25D50AEB, 0x94AEF68C, 0x0388E22D, 0x7262CDCE, 0xE13CB96F, 0x5016A510, + 0xBEF090B1, 0x2DCA7C52, 0x9CA467F3, 0x0B7E5394, 0x7A583F35, 0xE9322AD6, + 0x580C1677, 0xC6E60218, 0x35BFEDB9, 0xA499D95A, 0x1373C4FB, 0x824DB09C, + 0xF1279C3D, 0x600187DE, 0xCEDB737F, 0x3DB55F20, 0xAC8F4AC1, 0x1B693662, + 0x8A432203, 0xF91D0DA4, 0x67F6F945, 0xD6D0E4E6, 0x45AAD087, 0xB484BC28, + 0x235EA7C9, 0x9238936A, 0x01127F0B, 0x6FEC6AAC, 0xDEC6564D, 0x4DA041EE, + 0xBC7A2D8F, 0x2B541930, 0x9A2E04D1, 0x0907F072, 0x77E1DC13, 0xE6BBC7B4, + 0x5595B355, 0xC46F9EF6, 0x33498A97, 0xA2237638, 0x10FD61D9, 0x7FD74D7A, + 0xEEB1391B, 0x5D8B24BC, 0xCC65105D, 0x3B3EFBFE, 0xAA18E79F, 0x18F2D340, + 0x87CCBEE1, 0xF6A6AA82, 0x65809623, 0xD45A81C4, 0x43346D65, 0xB20E5906, + 0x20E844A7, 0x8FC23048, 0xFE9C1BE9, 0x6D76078A, 0xDC4FF32B, 0x4B29DECC, + 0xBA03CA6D, 0x28DDB60E, 0x97B7A1AF, 0x06918D50, 0x756B78F1, 0xE4456492, + 0x531F5033, 0xC1F93BD4, 0x30D32775, 0x9FAD1316, 0x0E86FEB7, 0x7D60EA58, + 0xEC3AD5F9, 0x5B14C19A, 0xC9EEAD3B, 0x38C898DC, 0xA7A2847D, 0x167C701E, + 0x85565BBF, 0xF4304760, 0x630A3301, 0xD1E41EA2, 0x40BE0A43, 0xAF97F5E4, + 0x1E71E185, 0x8D4BCD26, 0xFC25B8C7, 0x6AFFA468, 0xD9D99009, 0x48B37BAA, + 0xB78D674B, 0x266752EC, 0x95413E8D, 0x041B2A2E, 0x72F515CF, 0xE1CF0170, + 0x50A8ED11, 0xBF82D8B2, 0x2E5CC453, 0x9D36AFF4, 0x0C109B95, 0x7AEA8736, + 0xE9C472D7, 0x589E5E78, 0xC7784A19, 0x365235BA, 0xA52C215B, 0x14060CFC, + 0x82DFF89D, 0xF1B9E43E, 0x6093CFDF, 0xCF6DBB80, 0x3E47A721, 0xAD2192C2, + 0x1BFB7E63, 0x8AD56A04, 0xF9AF55A5, 0x68894146, 0xD7632CE7, 0x463D1888, + 0xB5170429, 0x23F0EFCA, 0x92CADB6B, 0x01A4C70C, 0x707EB2AD, 0xDF589E4E, + 0x4E3289EF, 0xBD0C7590, 0x2BE66131, 0x9AC04CD2, 0x099A3873, 0x78742414, + 0xE74E0FB5, 0x5627FB56, 0xC501E6F7, 0x33DBD298, 0xA2B5BE39, 0x118FA9DA, + 0x8069957B, 0xEF43811C, 0x5E1D6CBD, 0xCCF7585E, 0x3BD143FF, 0xAAAB2FA0, + 0x19851B41, 0x885F06E2, 0xF738F283, 0x6612DE24, 0xD4ECC9C5, 0x43C6B566, + 0xB2A0A107, 0x217A8CA8, 0x90547849, 0xFF2E63EA, 0x6E084F8B, 0xDCE23B2C, + 0x4BBC26CD, 0xBA96126E, 0x296FFE0F, 0x9849E9B0, 0x0723D551, 0x75FDC0F2, + 0xE4D7AC93, 0x53B19834, 0xC28B83D5, 0x31656F76, 0xA03F5B17, 0x0F1946B8 }; + + static const byte KEY_ROT[32] = { + 0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0A, 0x1B, 0x0C, + 0x1D, 0x0E, 0x1F, 0x10, 0x01, 0x12, 0x03, 0x14, 0x05, 0x16, + 0x07, 0x18, 0x09, 0x1A, 0x0B, 0x1C, 0x0D, 0x1E, 0x0F, 0x00, + 0x11, 0x02 }; + + MK.resize(48); + RK.resize(48); + + secure_vector K(8); + for(size_t i = 0; i != length; ++i) + K[i/4] = (K[i/4] << 8) + key[i]; + + u32bit A = K[0], B = K[1], C = K[2], D = K[3], + E = K[4], F = K[5], G = K[6], H = K[7]; + + for(size_t i = 0; i != 48; i += 4) + { + round1(G, H, KEY_MASK[4*i+ 0], KEY_ROT[(4*i+ 0) % 32]); + round2(F, G, KEY_MASK[4*i+ 1], KEY_ROT[(4*i+ 1) % 32]); + round3(E, F, KEY_MASK[4*i+ 2], KEY_ROT[(4*i+ 2) % 32]); + round1(D, E, KEY_MASK[4*i+ 3], KEY_ROT[(4*i+ 3) % 32]); + round2(C, D, KEY_MASK[4*i+ 4], KEY_ROT[(4*i+ 4) % 32]); + round3(B, C, KEY_MASK[4*i+ 5], KEY_ROT[(4*i+ 5) % 32]); + round1(A, B, KEY_MASK[4*i+ 6], KEY_ROT[(4*i+ 6) % 32]); + round2(H, A, KEY_MASK[4*i+ 7], KEY_ROT[(4*i+ 7) % 32]); + round1(G, H, KEY_MASK[4*i+ 8], KEY_ROT[(4*i+ 8) % 32]); + round2(F, G, KEY_MASK[4*i+ 9], KEY_ROT[(4*i+ 9) % 32]); + round3(E, F, KEY_MASK[4*i+10], KEY_ROT[(4*i+10) % 32]); + round1(D, E, KEY_MASK[4*i+11], KEY_ROT[(4*i+11) % 32]); + round2(C, D, KEY_MASK[4*i+12], KEY_ROT[(4*i+12) % 32]); + round3(B, C, KEY_MASK[4*i+13], KEY_ROT[(4*i+13) % 32]); + round1(A, B, KEY_MASK[4*i+14], KEY_ROT[(4*i+14) % 32]); + round2(H, A, KEY_MASK[4*i+15], KEY_ROT[(4*i+15) % 32]); + + RK[i ] = (A % 32); + RK[i+1] = (C % 32); + RK[i+2] = (E % 32); + RK[i+3] = (G % 32); + MK[i ] = H; + MK[i+1] = F; + MK[i+2] = D; + MK[i+3] = B; + } + } + +void CAST_256::clear() + { + zap(MK); + zap(RK); + } + +} diff --git a/src/lib/block/cast/cast256.h b/src/lib/block/cast/cast256.h new file mode 100644 index 000000000..cd4572c4d --- /dev/null +++ b/src/lib/block/cast/cast256.h @@ -0,0 +1,36 @@ +/* +* CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CAST256_H__ +#define BOTAN_CAST256_H__ + +#include + +namespace Botan { + +/** +* CAST-256 +*/ +class BOTAN_DLL CAST_256 : public Block_Cipher_Fixed_Params<16, 4, 32, 4> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "CAST-256"; } + BlockCipher* clone() const { return new CAST_256; } + private: + void key_schedule(const byte[], size_t); + + secure_vector MK; + secure_vector RK; + }; + +} + +#endif diff --git a/src/lib/block/cast/cast_sboxes.h b/src/lib/block/cast/cast_sboxes.h new file mode 100644 index 000000000..95578c4a0 --- /dev/null +++ b/src/lib/block/cast/cast_sboxes.h @@ -0,0 +1,197 @@ +/* +* S-Box Tables for CAST-128 and CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CAST_SBOX_TABLES_H__ +#define BOTAN_CAST_SBOX_TABLES_H__ + +#include + +namespace Botan { + +const u32bit CAST_SBOX1[256] = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, + 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, + 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, + 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, + 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, + 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, + 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, + 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, + 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, + 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, + 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, + 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, + 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, + 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, + 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, + 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, + 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, + 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, + 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, + 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, + 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, + 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; + +const u32bit CAST_SBOX2[256] = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, + 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, + 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, + 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, + 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, + 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, + 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, + 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, + 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, + 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, + 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, + 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, + 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, + 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, + 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, + 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, + 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, + 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, + 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, + 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, + 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, + 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; + +const u32bit CAST_SBOX3[256] = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, + 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, + 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, + 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, + 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, + 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, + 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, + 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, + 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, + 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, + 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, + 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, + 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, + 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, + 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, + 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, + 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, + 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, + 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, + 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, + 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, + 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; + +const u32bit CAST_SBOX4[256] = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, + 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, + 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, + 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, + 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, + 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, + 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, + 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, + 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, + 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, + 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, + 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, + 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, + 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, + 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, + 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, + 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, + 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, + 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, + 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, + 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, + 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; + +} + +#endif diff --git a/src/lib/block/cast/info.txt b/src/lib/block/cast/info.txt new file mode 100644 index 000000000..be4cb7510 --- /dev/null +++ b/src/lib/block/cast/info.txt @@ -0,0 +1,10 @@ +define CAST 20131128 + + +cast_sboxes.h + + + +cast128.h +cast256.h + diff --git a/src/lib/block/des/des.cpp b/src/lib/block/des/des.cpp new file mode 100644 index 000000000..a87b4d6bc --- /dev/null +++ b/src/lib/block/des/des.cpp @@ -0,0 +1,304 @@ +/* +* DES +* (C) 1999-2008 Jack Lloyd +* +* Based on a public domain implemenation by Phil Karn (who in turn +* credited Richard Outerbridge and Jim Gillogly) +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* DES Key Schedule +*/ +void des_key_schedule(u32bit round_key[32], const byte key[8]) + { + static const byte ROT[16] = { 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1 }; + + u32bit C = ((key[7] & 0x80) << 20) | ((key[6] & 0x80) << 19) | + ((key[5] & 0x80) << 18) | ((key[4] & 0x80) << 17) | + ((key[3] & 0x80) << 16) | ((key[2] & 0x80) << 15) | + ((key[1] & 0x80) << 14) | ((key[0] & 0x80) << 13) | + ((key[7] & 0x40) << 13) | ((key[6] & 0x40) << 12) | + ((key[5] & 0x40) << 11) | ((key[4] & 0x40) << 10) | + ((key[3] & 0x40) << 9) | ((key[2] & 0x40) << 8) | + ((key[1] & 0x40) << 7) | ((key[0] & 0x40) << 6) | + ((key[7] & 0x20) << 6) | ((key[6] & 0x20) << 5) | + ((key[5] & 0x20) << 4) | ((key[4] & 0x20) << 3) | + ((key[3] & 0x20) << 2) | ((key[2] & 0x20) << 1) | + ((key[1] & 0x20) ) | ((key[0] & 0x20) >> 1) | + ((key[7] & 0x10) >> 1) | ((key[6] & 0x10) >> 2) | + ((key[5] & 0x10) >> 3) | ((key[4] & 0x10) >> 4); + u32bit D = ((key[7] & 0x02) << 26) | ((key[6] & 0x02) << 25) | + ((key[5] & 0x02) << 24) | ((key[4] & 0x02) << 23) | + ((key[3] & 0x02) << 22) | ((key[2] & 0x02) << 21) | + ((key[1] & 0x02) << 20) | ((key[0] & 0x02) << 19) | + ((key[7] & 0x04) << 17) | ((key[6] & 0x04) << 16) | + ((key[5] & 0x04) << 15) | ((key[4] & 0x04) << 14) | + ((key[3] & 0x04) << 13) | ((key[2] & 0x04) << 12) | + ((key[1] & 0x04) << 11) | ((key[0] & 0x04) << 10) | + ((key[7] & 0x08) << 8) | ((key[6] & 0x08) << 7) | + ((key[5] & 0x08) << 6) | ((key[4] & 0x08) << 5) | + ((key[3] & 0x08) << 4) | ((key[2] & 0x08) << 3) | + ((key[1] & 0x08) << 2) | ((key[0] & 0x08) << 1) | + ((key[3] & 0x10) >> 1) | ((key[2] & 0x10) >> 2) | + ((key[1] & 0x10) >> 3) | ((key[0] & 0x10) >> 4); + + for(size_t i = 0; i != 16; ++i) + { + C = ((C << ROT[i]) | (C >> (28-ROT[i]))) & 0x0FFFFFFF; + D = ((D << ROT[i]) | (D >> (28-ROT[i]))) & 0x0FFFFFFF; + round_key[2*i ] = ((C & 0x00000010) << 22) | ((C & 0x00000800) << 17) | + ((C & 0x00000020) << 16) | ((C & 0x00004004) << 15) | + ((C & 0x00000200) << 11) | ((C & 0x00020000) << 10) | + ((C & 0x01000000) >> 6) | ((C & 0x00100000) >> 4) | + ((C & 0x00010000) << 3) | ((C & 0x08000000) >> 2) | + ((C & 0x00800000) << 1) | ((D & 0x00000010) << 8) | + ((D & 0x00000002) << 7) | ((D & 0x00000001) << 2) | + ((D & 0x00000200) ) | ((D & 0x00008000) >> 2) | + ((D & 0x00000088) >> 3) | ((D & 0x00001000) >> 7) | + ((D & 0x00080000) >> 9) | ((D & 0x02020000) >> 14) | + ((D & 0x00400000) >> 21); + round_key[2*i+1] = ((C & 0x00000001) << 28) | ((C & 0x00000082) << 18) | + ((C & 0x00002000) << 14) | ((C & 0x00000100) << 10) | + ((C & 0x00001000) << 9) | ((C & 0x00040000) << 6) | + ((C & 0x02400000) << 4) | ((C & 0x00008000) << 2) | + ((C & 0x00200000) >> 1) | ((C & 0x04000000) >> 10) | + ((D & 0x00000020) << 6) | ((D & 0x00000100) ) | + ((D & 0x00000800) >> 1) | ((D & 0x00000040) >> 3) | + ((D & 0x00010000) >> 4) | ((D & 0x00000400) >> 5) | + ((D & 0x00004000) >> 10) | ((D & 0x04000000) >> 13) | + ((D & 0x00800000) >> 14) | ((D & 0x00100000) >> 18) | + ((D & 0x01000000) >> 24) | ((D & 0x08000000) >> 26); + } + } + +/* +* DES Encryption +*/ +void des_encrypt(u32bit& L, u32bit& R, + const u32bit round_key[32]) + { + for(size_t i = 0; i != 16; i += 2) + { + u32bit T0, T1; + + T0 = rotate_right(R, 4) ^ round_key[2*i]; + T1 = R ^ round_key[2*i + 1]; + + L ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + + T0 = rotate_right(L, 4) ^ round_key[2*i + 2]; + T1 = L ^ round_key[2*i + 3]; + + R ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + } + } + +/* +* DES Decryption +*/ +void des_decrypt(u32bit& L, u32bit& R, + const u32bit round_key[32]) + { + for(size_t i = 16; i != 0; i -= 2) + { + u32bit T0, T1; + + T0 = rotate_right(R, 4) ^ round_key[2*i - 2]; + T1 = R ^ round_key[2*i - 1]; + + L ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + + T0 = rotate_right(L, 4) ^ round_key[2*i - 4]; + T1 = L ^ round_key[2*i - 3]; + + R ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + } + } + +} + +/* +* DES Encryption +*/ +void DES::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_encrypt(L, R, &round_key[0]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DES Decryption +*/ +void DES::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_decrypt(L, R, &round_key[0]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DES Key Schedule +*/ +void DES::key_schedule(const byte key[], size_t) + { + round_key.resize(32); + des_key_schedule(&round_key[0], key); + } + +void DES::clear() + { + zap(round_key); + } + +/* +* TripleDES Encryption +*/ +void TripleDES::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_encrypt(L, R, &round_key[0]); + des_decrypt(R, L, &round_key[32]); + des_encrypt(L, R, &round_key[64]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TripleDES Decryption +*/ +void TripleDES::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_decrypt(L, R, &round_key[64]); + des_encrypt(R, L, &round_key[32]); + des_decrypt(L, R, &round_key[0]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TripleDES Key Schedule +*/ +void TripleDES::key_schedule(const byte key[], size_t length) + { + round_key.resize(3*32); + des_key_schedule(&round_key[0], key); + des_key_schedule(&round_key[32], key + 8); + + if(length == 24) + des_key_schedule(&round_key[64], key + 16); + else + copy_mem(&round_key[64], &round_key[0], 32); + } + +void TripleDES::clear() + { + zap(round_key); + } + +} diff --git a/src/lib/block/des/des.h b/src/lib/block/des/des.h new file mode 100644 index 000000000..4f3811bcf --- /dev/null +++ b/src/lib/block/des/des.h @@ -0,0 +1,70 @@ +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DES_H__ +#define BOTAN_DES_H__ + +#include + +namespace Botan { + +/** +* DES +*/ +class BOTAN_DLL DES : public Block_Cipher_Fixed_Params<8, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "DES"; } + BlockCipher* clone() const { return new DES; } + private: + void key_schedule(const byte[], size_t); + + secure_vector round_key; + }; + +/** +* Triple DES +*/ +class BOTAN_DLL TripleDES : public Block_Cipher_Fixed_Params<8, 16, 24, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "TripleDES"; } + BlockCipher* clone() const { return new TripleDES; } + private: + void key_schedule(const byte[], size_t); + + secure_vector round_key; + }; + +/* +* DES Tables +*/ +extern const u32bit DES_SPBOX1[256]; +extern const u32bit DES_SPBOX2[256]; +extern const u32bit DES_SPBOX3[256]; +extern const u32bit DES_SPBOX4[256]; +extern const u32bit DES_SPBOX5[256]; +extern const u32bit DES_SPBOX6[256]; +extern const u32bit DES_SPBOX7[256]; +extern const u32bit DES_SPBOX8[256]; + +extern const u64bit DES_IPTAB1[256]; +extern const u64bit DES_IPTAB2[256]; +extern const u64bit DES_FPTAB1[256]; +extern const u64bit DES_FPTAB2[256]; + +} + +#endif diff --git a/src/lib/block/des/des_tab.cpp b/src/lib/block/des/des_tab.cpp new file mode 100644 index 000000000..b46ca3063 --- /dev/null +++ b/src/lib/block/des/des_tab.cpp @@ -0,0 +1,636 @@ +/* +* Substitution/Permutation Tables for DES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const u32bit DES_SPBOX1[256] = { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, + 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, + 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, + 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, + 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, + 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, + 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, + 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, + 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, + 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, + 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, + 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; + +const u32bit DES_SPBOX2[256] = { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, + 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, + 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, + 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, + 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, + 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, + 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, + 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, + 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, + 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, + 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, + 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; + +const u32bit DES_SPBOX3[256] = { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, + 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, + 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, + 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, + 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, + 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, + 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, + 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, + 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, + 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, + 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, + 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; + +const u32bit DES_SPBOX4[256] = { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, + 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, + 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; + +const u32bit DES_SPBOX5[256] = { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, + 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, + 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, + 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, + 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, + 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, + 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, + 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, + 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, + 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, + 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, + 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; + +const u32bit DES_SPBOX6[256] = { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, + 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, + 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, + 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, + 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, + 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, + 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, + 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, + 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, + 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, + 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, + 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; + +const u32bit DES_SPBOX7[256] = { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, + 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, + 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, + 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, + 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, + 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, + 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, + 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, + 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, + 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, + 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, + 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; + +const u32bit DES_SPBOX8[256] = { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, + 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, + 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, + 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, + 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, + 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, + 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, + 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, + 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, + 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, + 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, + 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; + +const u64bit DES_IPTAB1[256] = { +0x0000000000000000, 0x0000000200000000, 0x0000000000000002, 0x0000000200000002, +0x0000020000000000, 0x0000020200000000, 0x0000020000000002, 0x0000020200000002, +0x0000000000000200, 0x0000000200000200, 0x0000000000000202, 0x0000000200000202, +0x0000020000000200, 0x0000020200000200, 0x0000020000000202, 0x0000020200000202, +0x0002000000000000, 0x0002000200000000, 0x0002000000000002, 0x0002000200000002, +0x0002020000000000, 0x0002020200000000, 0x0002020000000002, 0x0002020200000002, +0x0002000000000200, 0x0002000200000200, 0x0002000000000202, 0x0002000200000202, +0x0002020000000200, 0x0002020200000200, 0x0002020000000202, 0x0002020200000202, +0x0000000000020000, 0x0000000200020000, 0x0000000000020002, 0x0000000200020002, +0x0000020000020000, 0x0000020200020000, 0x0000020000020002, 0x0000020200020002, +0x0000000000020200, 0x0000000200020200, 0x0000000000020202, 0x0000000200020202, +0x0000020000020200, 0x0000020200020200, 0x0000020000020202, 0x0000020200020202, +0x0002000000020000, 0x0002000200020000, 0x0002000000020002, 0x0002000200020002, +0x0002020000020000, 0x0002020200020000, 0x0002020000020002, 0x0002020200020002, +0x0002000000020200, 0x0002000200020200, 0x0002000000020202, 0x0002000200020202, +0x0002020000020200, 0x0002020200020200, 0x0002020000020202, 0x0002020200020202, +0x0200000000000000, 0x0200000200000000, 0x0200000000000002, 0x0200000200000002, +0x0200020000000000, 0x0200020200000000, 0x0200020000000002, 0x0200020200000002, +0x0200000000000200, 0x0200000200000200, 0x0200000000000202, 0x0200000200000202, +0x0200020000000200, 0x0200020200000200, 0x0200020000000202, 0x0200020200000202, +0x0202000000000000, 0x0202000200000000, 0x0202000000000002, 0x0202000200000002, +0x0202020000000000, 0x0202020200000000, 0x0202020000000002, 0x0202020200000002, +0x0202000000000200, 0x0202000200000200, 0x0202000000000202, 0x0202000200000202, +0x0202020000000200, 0x0202020200000200, 0x0202020000000202, 0x0202020200000202, +0x0200000000020000, 0x0200000200020000, 0x0200000000020002, 0x0200000200020002, +0x0200020000020000, 0x0200020200020000, 0x0200020000020002, 0x0200020200020002, +0x0200000000020200, 0x0200000200020200, 0x0200000000020202, 0x0200000200020202, +0x0200020000020200, 0x0200020200020200, 0x0200020000020202, 0x0200020200020202, +0x0202000000020000, 0x0202000200020000, 0x0202000000020002, 0x0202000200020002, +0x0202020000020000, 0x0202020200020000, 0x0202020000020002, 0x0202020200020002, +0x0202000000020200, 0x0202000200020200, 0x0202000000020202, 0x0202000200020202, +0x0202020000020200, 0x0202020200020200, 0x0202020000020202, 0x0202020200020202, +0x0000000002000000, 0x0000000202000000, 0x0000000002000002, 0x0000000202000002, +0x0000020002000000, 0x0000020202000000, 0x0000020002000002, 0x0000020202000002, +0x0000000002000200, 0x0000000202000200, 0x0000000002000202, 0x0000000202000202, +0x0000020002000200, 0x0000020202000200, 0x0000020002000202, 0x0000020202000202, +0x0002000002000000, 0x0002000202000000, 0x0002000002000002, 0x0002000202000002, +0x0002020002000000, 0x0002020202000000, 0x0002020002000002, 0x0002020202000002, +0x0002000002000200, 0x0002000202000200, 0x0002000002000202, 0x0002000202000202, +0x0002020002000200, 0x0002020202000200, 0x0002020002000202, 0x0002020202000202, +0x0000000002020000, 0x0000000202020000, 0x0000000002020002, 0x0000000202020002, +0x0000020002020000, 0x0000020202020000, 0x0000020002020002, 0x0000020202020002, +0x0000000002020200, 0x0000000202020200, 0x0000000002020202, 0x0000000202020202, +0x0000020002020200, 0x0000020202020200, 0x0000020002020202, 0x0000020202020202, +0x0002000002020000, 0x0002000202020000, 0x0002000002020002, 0x0002000202020002, +0x0002020002020000, 0x0002020202020000, 0x0002020002020002, 0x0002020202020002, +0x0002000002020200, 0x0002000202020200, 0x0002000002020202, 0x0002000202020202, +0x0002020002020200, 0x0002020202020200, 0x0002020002020202, 0x0002020202020202, +0x0200000002000000, 0x0200000202000000, 0x0200000002000002, 0x0200000202000002, +0x0200020002000000, 0x0200020202000000, 0x0200020002000002, 0x0200020202000002, +0x0200000002000200, 0x0200000202000200, 0x0200000002000202, 0x0200000202000202, +0x0200020002000200, 0x0200020202000200, 0x0200020002000202, 0x0200020202000202, +0x0202000002000000, 0x0202000202000000, 0x0202000002000002, 0x0202000202000002, +0x0202020002000000, 0x0202020202000000, 0x0202020002000002, 0x0202020202000002, +0x0202000002000200, 0x0202000202000200, 0x0202000002000202, 0x0202000202000202, +0x0202020002000200, 0x0202020202000200, 0x0202020002000202, 0x0202020202000202, +0x0200000002020000, 0x0200000202020000, 0x0200000002020002, 0x0200000202020002, +0x0200020002020000, 0x0200020202020000, 0x0200020002020002, 0x0200020202020002, +0x0200000002020200, 0x0200000202020200, 0x0200000002020202, 0x0200000202020202, +0x0200020002020200, 0x0200020202020200, 0x0200020002020202, 0x0200020202020202, +0x0202000002020000, 0x0202000202020000, 0x0202000002020002, 0x0202000202020002, +0x0202020002020000, 0x0202020202020000, 0x0202020002020002, 0x0202020202020002, +0x0202000002020200, 0x0202000202020200, 0x0202000002020202, 0x0202000202020202, +0x0202020002020200, 0x0202020202020200, 0x0202020002020202, 0x0202020202020202 }; + +const u64bit DES_IPTAB2[256] = { +0x0000000000000000, 0x0000010000000000, 0x0000000000000100, 0x0000010000000100, +0x0001000000000000, 0x0001010000000000, 0x0001000000000100, 0x0001010000000100, +0x0000000000010000, 0x0000010000010000, 0x0000000000010100, 0x0000010000010100, +0x0001000000010000, 0x0001010000010000, 0x0001000000010100, 0x0001010000010100, +0x0100000000000000, 0x0100010000000000, 0x0100000000000100, 0x0100010000000100, +0x0101000000000000, 0x0101010000000000, 0x0101000000000100, 0x0101010000000100, +0x0100000000010000, 0x0100010000010000, 0x0100000000010100, 0x0100010000010100, +0x0101000000010000, 0x0101010000010000, 0x0101000000010100, 0x0101010000010100, +0x0000000001000000, 0x0000010001000000, 0x0000000001000100, 0x0000010001000100, +0x0001000001000000, 0x0001010001000000, 0x0001000001000100, 0x0001010001000100, +0x0000000001010000, 0x0000010001010000, 0x0000000001010100, 0x0000010001010100, +0x0001000001010000, 0x0001010001010000, 0x0001000001010100, 0x0001010001010100, +0x0100000001000000, 0x0100010001000000, 0x0100000001000100, 0x0100010001000100, +0x0101000001000000, 0x0101010001000000, 0x0101000001000100, 0x0101010001000100, +0x0100000001010000, 0x0100010001010000, 0x0100000001010100, 0x0100010001010100, +0x0101000001010000, 0x0101010001010000, 0x0101000001010100, 0x0101010001010100, +0x0000000100000000, 0x0000010100000000, 0x0000000100000100, 0x0000010100000100, +0x0001000100000000, 0x0001010100000000, 0x0001000100000100, 0x0001010100000100, +0x0000000100010000, 0x0000010100010000, 0x0000000100010100, 0x0000010100010100, +0x0001000100010000, 0x0001010100010000, 0x0001000100010100, 0x0001010100010100, +0x0100000100000000, 0x0100010100000000, 0x0100000100000100, 0x0100010100000100, +0x0101000100000000, 0x0101010100000000, 0x0101000100000100, 0x0101010100000100, +0x0100000100010000, 0x0100010100010000, 0x0100000100010100, 0x0100010100010100, +0x0101000100010000, 0x0101010100010000, 0x0101000100010100, 0x0101010100010100, +0x0000000101000000, 0x0000010101000000, 0x0000000101000100, 0x0000010101000100, +0x0001000101000000, 0x0001010101000000, 0x0001000101000100, 0x0001010101000100, +0x0000000101010000, 0x0000010101010000, 0x0000000101010100, 0x0000010101010100, +0x0001000101010000, 0x0001010101010000, 0x0001000101010100, 0x0001010101010100, +0x0100000101000000, 0x0100010101000000, 0x0100000101000100, 0x0100010101000100, +0x0101000101000000, 0x0101010101000000, 0x0101000101000100, 0x0101010101000100, +0x0100000101010000, 0x0100010101010000, 0x0100000101010100, 0x0100010101010100, +0x0101000101010000, 0x0101010101010000, 0x0101000101010100, 0x0101010101010100, +0x0000000000000001, 0x0000010000000001, 0x0000000000000101, 0x0000010000000101, +0x0001000000000001, 0x0001010000000001, 0x0001000000000101, 0x0001010000000101, +0x0000000000010001, 0x0000010000010001, 0x0000000000010101, 0x0000010000010101, +0x0001000000010001, 0x0001010000010001, 0x0001000000010101, 0x0001010000010101, +0x0100000000000001, 0x0100010000000001, 0x0100000000000101, 0x0100010000000101, +0x0101000000000001, 0x0101010000000001, 0x0101000000000101, 0x0101010000000101, +0x0100000000010001, 0x0100010000010001, 0x0100000000010101, 0x0100010000010101, +0x0101000000010001, 0x0101010000010001, 0x0101000000010101, 0x0101010000010101, +0x0000000001000001, 0x0000010001000001, 0x0000000001000101, 0x0000010001000101, +0x0001000001000001, 0x0001010001000001, 0x0001000001000101, 0x0001010001000101, +0x0000000001010001, 0x0000010001010001, 0x0000000001010101, 0x0000010001010101, +0x0001000001010001, 0x0001010001010001, 0x0001000001010101, 0x0001010001010101, +0x0100000001000001, 0x0100010001000001, 0x0100000001000101, 0x0100010001000101, +0x0101000001000001, 0x0101010001000001, 0x0101000001000101, 0x0101010001000101, +0x0100000001010001, 0x0100010001010001, 0x0100000001010101, 0x0100010001010101, +0x0101000001010001, 0x0101010001010001, 0x0101000001010101, 0x0101010001010101, +0x0000000100000001, 0x0000010100000001, 0x0000000100000101, 0x0000010100000101, +0x0001000100000001, 0x0001010100000001, 0x0001000100000101, 0x0001010100000101, +0x0000000100010001, 0x0000010100010001, 0x0000000100010101, 0x0000010100010101, +0x0001000100010001, 0x0001010100010001, 0x0001000100010101, 0x0001010100010101, +0x0100000100000001, 0x0100010100000001, 0x0100000100000101, 0x0100010100000101, +0x0101000100000001, 0x0101010100000001, 0x0101000100000101, 0x0101010100000101, +0x0100000100010001, 0x0100010100010001, 0x0100000100010101, 0x0100010100010101, +0x0101000100010001, 0x0101010100010001, 0x0101000100010101, 0x0101010100010101, +0x0000000101000001, 0x0000010101000001, 0x0000000101000101, 0x0000010101000101, +0x0001000101000001, 0x0001010101000001, 0x0001000101000101, 0x0001010101000101, +0x0000000101010001, 0x0000010101010001, 0x0000000101010101, 0x0000010101010101, +0x0001000101010001, 0x0001010101010001, 0x0001000101010101, 0x0001010101010101, +0x0100000101000001, 0x0100010101000001, 0x0100000101000101, 0x0100010101000101, +0x0101000101000001, 0x0101010101000001, 0x0101000101000101, 0x0101010101000101, +0x0100000101010001, 0x0100010101010001, 0x0100000101010101, 0x0100010101010101, +0x0101000101010001, 0x0101010101010001, 0x0101000101010101, 0x0101010101010101 }; + +const u64bit DES_FPTAB1[256] = { +0x0000000000000000, 0x0000000100000000, 0x0000000004000000, 0x0000000104000000, +0x0000000000040000, 0x0000000100040000, 0x0000000004040000, 0x0000000104040000, +0x0000000000000400, 0x0000000100000400, 0x0000000004000400, 0x0000000104000400, +0x0000000000040400, 0x0000000100040400, 0x0000000004040400, 0x0000000104040400, +0x0000000000000004, 0x0000000100000004, 0x0000000004000004, 0x0000000104000004, +0x0000000000040004, 0x0000000100040004, 0x0000000004040004, 0x0000000104040004, +0x0000000000000404, 0x0000000100000404, 0x0000000004000404, 0x0000000104000404, +0x0000000000040404, 0x0000000100040404, 0x0000000004040404, 0x0000000104040404, +0x0400000000000000, 0x0400000100000000, 0x0400000004000000, 0x0400000104000000, +0x0400000000040000, 0x0400000100040000, 0x0400000004040000, 0x0400000104040000, +0x0400000000000400, 0x0400000100000400, 0x0400000004000400, 0x0400000104000400, +0x0400000000040400, 0x0400000100040400, 0x0400000004040400, 0x0400000104040400, +0x0400000000000004, 0x0400000100000004, 0x0400000004000004, 0x0400000104000004, +0x0400000000040004, 0x0400000100040004, 0x0400000004040004, 0x0400000104040004, +0x0400000000000404, 0x0400000100000404, 0x0400000004000404, 0x0400000104000404, +0x0400000000040404, 0x0400000100040404, 0x0400000004040404, 0x0400000104040404, +0x0004000000000000, 0x0004000100000000, 0x0004000004000000, 0x0004000104000000, +0x0004000000040000, 0x0004000100040000, 0x0004000004040000, 0x0004000104040000, +0x0004000000000400, 0x0004000100000400, 0x0004000004000400, 0x0004000104000400, +0x0004000000040400, 0x0004000100040400, 0x0004000004040400, 0x0004000104040400, +0x0004000000000004, 0x0004000100000004, 0x0004000004000004, 0x0004000104000004, +0x0004000000040004, 0x0004000100040004, 0x0004000004040004, 0x0004000104040004, +0x0004000000000404, 0x0004000100000404, 0x0004000004000404, 0x0004000104000404, +0x0004000000040404, 0x0004000100040404, 0x0004000004040404, 0x0004000104040404, +0x0404000000000000, 0x0404000100000000, 0x0404000004000000, 0x0404000104000000, +0x0404000000040000, 0x0404000100040000, 0x0404000004040000, 0x0404000104040000, +0x0404000000000400, 0x0404000100000400, 0x0404000004000400, 0x0404000104000400, +0x0404000000040400, 0x0404000100040400, 0x0404000004040400, 0x0404000104040400, +0x0404000000000004, 0x0404000100000004, 0x0404000004000004, 0x0404000104000004, +0x0404000000040004, 0x0404000100040004, 0x0404000004040004, 0x0404000104040004, +0x0404000000000404, 0x0404000100000404, 0x0404000004000404, 0x0404000104000404, +0x0404000000040404, 0x0404000100040404, 0x0404000004040404, 0x0404000104040404, +0x0000040000000000, 0x0000040100000000, 0x0000040004000000, 0x0000040104000000, +0x0000040000040000, 0x0000040100040000, 0x0000040004040000, 0x0000040104040000, +0x0000040000000400, 0x0000040100000400, 0x0000040004000400, 0x0000040104000400, +0x0000040000040400, 0x0000040100040400, 0x0000040004040400, 0x0000040104040400, +0x0000040000000004, 0x0000040100000004, 0x0000040004000004, 0x0000040104000004, +0x0000040000040004, 0x0000040100040004, 0x0000040004040004, 0x0000040104040004, +0x0000040000000404, 0x0000040100000404, 0x0000040004000404, 0x0000040104000404, +0x0000040000040404, 0x0000040100040404, 0x0000040004040404, 0x0000040104040404, +0x0400040000000000, 0x0400040100000000, 0x0400040004000000, 0x0400040104000000, +0x0400040000040000, 0x0400040100040000, 0x0400040004040000, 0x0400040104040000, +0x0400040000000400, 0x0400040100000400, 0x0400040004000400, 0x0400040104000400, +0x0400040000040400, 0x0400040100040400, 0x0400040004040400, 0x0400040104040400, +0x0400040000000004, 0x0400040100000004, 0x0400040004000004, 0x0400040104000004, +0x0400040000040004, 0x0400040100040004, 0x0400040004040004, 0x0400040104040004, +0x0400040000000404, 0x0400040100000404, 0x0400040004000404, 0x0400040104000404, +0x0400040000040404, 0x0400040100040404, 0x0400040004040404, 0x0400040104040404, +0x0004040000000000, 0x0004040100000000, 0x0004040004000000, 0x0004040104000000, +0x0004040000040000, 0x0004040100040000, 0x0004040004040000, 0x0004040104040000, +0x0004040000000400, 0x0004040100000400, 0x0004040004000400, 0x0004040104000400, +0x0004040000040400, 0x0004040100040400, 0x0004040004040400, 0x0004040104040400, +0x0004040000000004, 0x0004040100000004, 0x0004040004000004, 0x0004040104000004, +0x0004040000040004, 0x0004040100040004, 0x0004040004040004, 0x0004040104040004, +0x0004040000000404, 0x0004040100000404, 0x0004040004000404, 0x0004040104000404, +0x0004040000040404, 0x0004040100040404, 0x0004040004040404, 0x0004040104040404, +0x0404040000000000, 0x0404040100000000, 0x0404040004000000, 0x0404040104000000, +0x0404040000040000, 0x0404040100040000, 0x0404040004040000, 0x0404040104040000, +0x0404040000000400, 0x0404040100000400, 0x0404040004000400, 0x0404040104000400, +0x0404040000040400, 0x0404040100040400, 0x0404040004040400, 0x0404040104040400, +0x0404040000000004, 0x0404040100000004, 0x0404040004000004, 0x0404040104000004, +0x0404040000040004, 0x0404040100040004, 0x0404040004040004, 0x0404040104040004, +0x0404040000000404, 0x0404040100000404, 0x0404040004000404, 0x0404040104000404, +0x0404040000040404, 0x0404040100040404, 0x0404040004040404, 0x0404040104040404 }; + +const u64bit DES_FPTAB2[256] = { +0x0000000000000000, 0x0000004000000000, 0x0000000001000000, 0x0000004001000000, +0x0000000000010000, 0x0000004000010000, 0x0000000001010000, 0x0000004001010000, +0x0000000000000100, 0x0000004000000100, 0x0000000001000100, 0x0000004001000100, +0x0000000000010100, 0x0000004000010100, 0x0000000001010100, 0x0000004001010100, +0x0000000000000001, 0x0000004000000001, 0x0000000001000001, 0x0000004001000001, +0x0000000000010001, 0x0000004000010001, 0x0000000001010001, 0x0000004001010001, +0x0000000000000101, 0x0000004000000101, 0x0000000001000101, 0x0000004001000101, +0x0000000000010101, 0x0000004000010101, 0x0000000001010101, 0x0000004001010101, +0x0100000000000000, 0x0100004000000000, 0x0100000001000000, 0x0100004001000000, +0x0100000000010000, 0x0100004000010000, 0x0100000001010000, 0x0100004001010000, +0x0100000000000100, 0x0100004000000100, 0x0100000001000100, 0x0100004001000100, +0x0100000000010100, 0x0100004000010100, 0x0100000001010100, 0x0100004001010100, +0x0100000000000001, 0x0100004000000001, 0x0100000001000001, 0x0100004001000001, +0x0100000000010001, 0x0100004000010001, 0x0100000001010001, 0x0100004001010001, +0x0100000000000101, 0x0100004000000101, 0x0100000001000101, 0x0100004001000101, +0x0100000000010101, 0x0100004000010101, 0x0100000001010101, 0x0100004001010101, +0x0001000000000000, 0x0001004000000000, 0x0001000001000000, 0x0001004001000000, +0x0001000000010000, 0x0001004000010000, 0x0001000001010000, 0x0001004001010000, +0x0001000000000100, 0x0001004000000100, 0x0001000001000100, 0x0001004001000100, +0x0001000000010100, 0x0001004000010100, 0x0001000001010100, 0x0001004001010100, +0x0001000000000001, 0x0001004000000001, 0x0001000001000001, 0x0001004001000001, +0x0001000000010001, 0x0001004000010001, 0x0001000001010001, 0x0001004001010001, +0x0001000000000101, 0x0001004000000101, 0x0001000001000101, 0x0001004001000101, +0x0001000000010101, 0x0001004000010101, 0x0001000001010101, 0x0001004001010101, +0x0101000000000000, 0x0101004000000000, 0x0101000001000000, 0x0101004001000000, +0x0101000000010000, 0x0101004000010000, 0x0101000001010000, 0x0101004001010000, +0x0101000000000100, 0x0101004000000100, 0x0101000001000100, 0x0101004001000100, +0x0101000000010100, 0x0101004000010100, 0x0101000001010100, 0x0101004001010100, +0x0101000000000001, 0x0101004000000001, 0x0101000001000001, 0x0101004001000001, +0x0101000000010001, 0x0101004000010001, 0x0101000001010001, 0x0101004001010001, +0x0101000000000101, 0x0101004000000101, 0x0101000001000101, 0x0101004001000101, +0x0101000000010101, 0x0101004000010101, 0x0101000001010101, 0x0101004001010101, +0x0000010000000000, 0x0000014000000000, 0x0000010001000000, 0x0000014001000000, +0x0000010000010000, 0x0000014000010000, 0x0000010001010000, 0x0000014001010000, +0x0000010000000100, 0x0000014000000100, 0x0000010001000100, 0x0000014001000100, +0x0000010000010100, 0x0000014000010100, 0x0000010001010100, 0x0000014001010100, +0x0000010000000001, 0x0000014000000001, 0x0000010001000001, 0x0000014001000001, +0x0000010000010001, 0x0000014000010001, 0x0000010001010001, 0x0000014001010001, +0x0000010000000101, 0x0000014000000101, 0x0000010001000101, 0x0000014001000101, +0x0000010000010101, 0x0000014000010101, 0x0000010001010101, 0x0000014001010101, +0x0100010000000000, 0x0100014000000000, 0x0100010001000000, 0x0100014001000000, +0x0100010000010000, 0x0100014000010000, 0x0100010001010000, 0x0100014001010000, +0x0100010000000100, 0x0100014000000100, 0x0100010001000100, 0x0100014001000100, +0x0100010000010100, 0x0100014000010100, 0x0100010001010100, 0x0100014001010100, +0x0100010000000001, 0x0100014000000001, 0x0100010001000001, 0x0100014001000001, +0x0100010000010001, 0x0100014000010001, 0x0100010001010001, 0x0100014001010001, +0x0100010000000101, 0x0100014000000101, 0x0100010001000101, 0x0100014001000101, +0x0100010000010101, 0x0100014000010101, 0x0100010001010101, 0x0100014001010101, +0x0001010000000000, 0x0001014000000000, 0x0001010001000000, 0x0001014001000000, +0x0001010000010000, 0x0001014000010000, 0x0001010001010000, 0x0001014001010000, +0x0001010000000100, 0x0001014000000100, 0x0001010001000100, 0x0001014001000100, +0x0001010000010100, 0x0001014000010100, 0x0001010001010100, 0x0001014001010100, +0x0001010000000001, 0x0001014000000001, 0x0001010001000001, 0x0001014001000001, +0x0001010000010001, 0x0001014000010001, 0x0001010001010001, 0x0001014001010001, +0x0001010000000101, 0x0001014000000101, 0x0001010001000101, 0x0001014001000101, +0x0001010000010101, 0x0001014000010101, 0x0001010001010101, 0x0001014001010101, +0x0101010000000000, 0x0101014000000000, 0x0101010001000000, 0x0101014001000000, +0x0101010000010000, 0x0101014000010000, 0x0101010001010000, 0x0101014001010000, +0x0101010000000100, 0x0101014000000100, 0x0101010001000100, 0x0101014001000100, +0x0101010000010100, 0x0101014000010100, 0x0101010001010100, 0x0101014001010100, +0x0101010000000001, 0x0101014000000001, 0x0101010001000001, 0x0101014001000001, +0x0101010000010001, 0x0101014000010001, 0x0101010001010001, 0x0101014001010001, +0x0101010000000101, 0x0101014000000101, 0x0101010001000101, 0x0101014001000101, +0x0101010000010101, 0x0101014000010101, 0x0101010001010101, 0x0101014001010101 }; + +} diff --git a/src/lib/block/des/desx.cpp b/src/lib/block/des/desx.cpp new file mode 100644 index 000000000..879e73ee9 --- /dev/null +++ b/src/lib/block/des/desx.cpp @@ -0,0 +1,62 @@ +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* DESX Encryption +*/ +void DESX::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, &K1[0], BLOCK_SIZE); + des.encrypt(out); + xor_buf(out, &K2[0], BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Decryption +*/ +void DESX::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, &K2[0], BLOCK_SIZE); + des.decrypt(out); + xor_buf(out, &K1[0], BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Key Schedule +*/ +void DESX::key_schedule(const byte key[], size_t) + { + K1.assign(key, key + 8); + des.set_key(key + 8, 8); + K2.assign(key + 16, key + 24); + } + +void DESX::clear() + { + des.clear(); + zap(K1); + zap(K2); + } + +} diff --git a/src/lib/block/des/desx.h b/src/lib/block/des/desx.h new file mode 100644 index 000000000..aeda3f3c4 --- /dev/null +++ b/src/lib/block/des/desx.h @@ -0,0 +1,35 @@ +/* +* DESX +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DESX_H__ +#define BOTAN_DESX_H__ + +#include + +namespace Botan { + +/** +* DESX +*/ +class BOTAN_DLL DESX : public Block_Cipher_Fixed_Params<8, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "DESX"; } + BlockCipher* clone() const { return new DESX; } + private: + void key_schedule(const byte[], size_t); + secure_vector K1, K2; + DES des; + }; + +} + +#endif diff --git a/src/lib/block/des/info.txt b/src/lib/block/des/info.txt new file mode 100644 index 000000000..a5d50d56e --- /dev/null +++ b/src/lib/block/des/info.txt @@ -0,0 +1 @@ +define DES 20131128 diff --git a/src/lib/block/gost_28147/gost_28147.cpp b/src/lib/block/gost_28147/gost_28147.cpp new file mode 100644 index 000000000..09ca9a57e --- /dev/null +++ b/src/lib/block/gost_28147/gost_28147.cpp @@ -0,0 +1,177 @@ +/* +* GOST 28147-89 +* (C) 1999-2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +byte GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const + { + byte x = sboxes[4 * col + (row / 2)]; + + return (row % 2 == 0) ? (x >> 4) : (x & 0x0F); + } + +GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : name(n) + { + // Encoded in the packed fromat from RFC 4357 + + // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0) + static const byte GOST_R_3411_TEST_PARAMS[64] = { + 0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A, + 0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38, + 0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62, + 0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3, + 0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C, + 0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC }; + + // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1) + static const byte GOST_R_3411_CRYPTOPRO_PARAMS[64] = { + 0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42, + 0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F, + 0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1, + 0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87, + 0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE, + 0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC }; + + if(name == "R3411_94_TestParam") + sboxes = GOST_R_3411_TEST_PARAMS; + else if(name == "R3411_CryptoPro") + sboxes = GOST_R_3411_CRYPTOPRO_PARAMS; + else + throw Invalid_Argument("GOST_28147_89_Params: Unknown " + name); + } + +/* +* GOST Constructor +*/ +GOST_28147_89::GOST_28147_89(const GOST_28147_89_Params& param) : SBOX(1024) + { + // Convert the parallel 4x4 sboxes into larger word-based sboxes + for(size_t i = 0; i != 4; ++i) + for(size_t j = 0; j != 256; ++j) + { + const u32bit T = (param.sbox_entry(2*i , j % 16)) | + (param.sbox_entry(2*i+1, j / 16) << 4); + SBOX[256*i+j] = rotate_left(T, (11+8*i) % 32); + } + } + +std::string GOST_28147_89::name() const + { + /* + 'Guess' the right name for the sbox on the basis of the values. + This would need to be updated if support for other sbox parameters + is added. Preferably, we would just store the string value in the + constructor, but can't break binary compat. + */ + std::string sbox_name = ""; + if(SBOX[0] == 0x00072000) + sbox_name = "R3411_94_TestParam"; + else if(SBOX[0] == 0x0002D000) + sbox_name = "R3411_CryptoPro"; + else + throw Internal_Error("GOST-28147 unrecognized sbox value"); + + return "GOST-28147-89(" + sbox_name + ")"; + } + +/* +* Two rounds of GOST +*/ +#define GOST_2ROUND(N1, N2, R1, R2) \ + do { \ + u32bit T0 = N1 + EK[R1]; \ + N2 ^= SBOX[get_byte(3, T0)] | \ + SBOX[get_byte(2, T0)+256] | \ + SBOX[get_byte(1, T0)+512] | \ + SBOX[get_byte(0, T0)+768]; \ + \ + u32bit T1 = N2 + EK[R2]; \ + N1 ^= SBOX[get_byte(3, T1)] | \ + SBOX[get_byte(2, T1)+256] | \ + SBOX[get_byte(1, T1)+512] | \ + SBOX[get_byte(0, T1)+768]; \ + } while(0) + +/* +* GOST Encryption +*/ +void GOST_28147_89::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit N1 = load_le(in, 0); + u32bit N2 = load_le(in, 1); + + for(size_t j = 0; j != 3; ++j) + { + GOST_2ROUND(N1, N2, 0, 1); + GOST_2ROUND(N1, N2, 2, 3); + GOST_2ROUND(N1, N2, 4, 5); + GOST_2ROUND(N1, N2, 6, 7); + } + + GOST_2ROUND(N1, N2, 7, 6); + GOST_2ROUND(N1, N2, 5, 4); + GOST_2ROUND(N1, N2, 3, 2); + GOST_2ROUND(N1, N2, 1, 0); + + store_le(out, N2, N1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* GOST Decryption +*/ +void GOST_28147_89::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit N1 = load_le(in, 0); + u32bit N2 = load_le(in, 1); + + GOST_2ROUND(N1, N2, 0, 1); + GOST_2ROUND(N1, N2, 2, 3); + GOST_2ROUND(N1, N2, 4, 5); + GOST_2ROUND(N1, N2, 6, 7); + + for(size_t j = 0; j != 3; ++j) + { + GOST_2ROUND(N1, N2, 7, 6); + GOST_2ROUND(N1, N2, 5, 4); + GOST_2ROUND(N1, N2, 3, 2); + GOST_2ROUND(N1, N2, 1, 0); + } + + store_le(out, N2, N1); + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* GOST Key Schedule +*/ +void GOST_28147_89::key_schedule(const byte key[], size_t) + { + EK.resize(8); + for(size_t i = 0; i != 8; ++i) + EK[i] = load_le(key, i); + } + +void GOST_28147_89::clear() + { + zap(EK); + } + +} diff --git a/src/lib/block/gost_28147/gost_28147.h b/src/lib/block/gost_28147/gost_28147.h new file mode 100644 index 000000000..34b99197e --- /dev/null +++ b/src/lib/block/gost_28147/gost_28147.h @@ -0,0 +1,84 @@ +/* +* GOST 28147-89 +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GOST_28147_89_H__ +#define BOTAN_GOST_28147_89_H__ + +#include + +namespace Botan { + +/** +* The GOST 28147-89 block cipher uses a set of 4 bit Sboxes, however +* the standard does not actually define these Sboxes; they are +* considered a local configuration issue. Several different sets are +* used. +*/ +class BOTAN_DLL GOST_28147_89_Params + { + public: + /** + * @param row the row + * @param col the column + * @return sbox entry at this row/column + */ + byte sbox_entry(size_t row, size_t col) const; + + /** + * @return name of this parameter set + */ + std::string param_name() const { return name; } + + /** + * Default GOST parameters are the ones given in GOST R 34.11 for + * testing purposes; these sboxes are also used by Crypto++, and, + * at least according to Wikipedia, the Central Bank of Russian + * Federation + * @param name of the parameter set + */ + GOST_28147_89_Params(const std::string& name = "R3411_94_TestParam"); + private: + const byte* sboxes; + std::string name; + }; + +/** +* GOST 28147-89 +*/ +class BOTAN_DLL GOST_28147_89 : public Block_Cipher_Fixed_Params<8, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const; + BlockCipher* clone() const { return new GOST_28147_89(SBOX); } + + /** + * @param params the sbox parameters to use + */ + GOST_28147_89(const GOST_28147_89_Params& params); + private: + GOST_28147_89(const std::vector& other_SBOX) : + SBOX(other_SBOX), EK(8) {} + + void key_schedule(const byte[], size_t); + + /* + * The sbox is not secret, this is just a larger expansion of it + * which we generate at runtime for faster execution + */ + std::vector SBOX; + + secure_vector EK; + }; + +} + +#endif diff --git a/src/lib/block/gost_28147/info.txt b/src/lib/block/gost_28147/info.txt new file mode 100644 index 000000000..396557248 --- /dev/null +++ b/src/lib/block/gost_28147/info.txt @@ -0,0 +1 @@ +define GOST_28147_89 20131128 diff --git a/src/lib/block/idea/idea.cpp b/src/lib/block/idea/idea.cpp new file mode 100644 index 000000000..61a938c57 --- /dev/null +++ b/src/lib/block/idea/idea.cpp @@ -0,0 +1,169 @@ +/* +* IDEA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* Multiplication modulo 65537 +*/ +inline u16bit mul(u16bit x, u16bit y) + { + const u32bit P = static_cast(x) * y; + + // P ? 0xFFFF : 0 + const u16bit P_mask = !P - 1; + + const u32bit P_hi = P >> 16; + const u32bit P_lo = P & 0xFFFF; + + const u16bit r_1 = (P_lo - P_hi) + (P_lo < P_hi); + const u16bit r_2 = 1 - x - y; + + return (r_1 & P_mask) | (r_2 & ~P_mask); + } + +/* +* Find multiplicative inverses modulo 65537 +* +* 65537 is prime; thus Fermat's little theorem tells us that +* x^65537 == x modulo 65537, which means +* x^(65537-2) == x^-1 modulo 65537 since +* x^(65537-2) * x == 1 mod 65537 +* +* Do the exponentiation with a basic square and multiply: all bits are +* of exponent are 1 so we always multiply +*/ +u16bit mul_inv(u16bit x) + { + u16bit y = x; + + for(size_t i = 0; i != 15; ++i) + { + y = mul(y, y); // square + y = mul(y, x); + } + + return y; + } + +/** +* IDEA is involutional, depending only on the key schedule +*/ +void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52]) + { + const size_t BLOCK_SIZE = 8; + + for(size_t i = 0; i != blocks; ++i) + { + u16bit X1 = load_be(in, 0); + u16bit X2 = load_be(in, 1); + u16bit X3 = load_be(in, 2); + u16bit X4 = load_be(in, 3); + + for(size_t j = 0; j != 8; ++j) + { + X1 = mul(X1, K[6*j+0]); + X2 += K[6*j+1]; + X3 += K[6*j+2]; + X4 = mul(X4, K[6*j+3]); + + u16bit T0 = X3; + X3 = mul(X3 ^ X1, K[6*j+4]); + + u16bit T1 = X2; + X2 = mul((X2 ^ X4) + X3, K[6*j+5]); + X3 += X2; + + X1 ^= X2; + X4 ^= X3; + X2 ^= T0; + X3 ^= T1; + } + + X1 = mul(X1, K[48]); + X2 += K[50]; + X3 += K[49]; + X4 = mul(X4, K[51]); + + store_be(out, X1, X3, X2, X4); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +} + +/* +* IDEA Encryption +*/ +void IDEA::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + idea_op(in, out, blocks, &EK[0]); + } + +/* +* IDEA Decryption +*/ +void IDEA::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + idea_op(in, out, blocks, &DK[0]); + } + +/* +* IDEA Key Schedule +*/ +void IDEA::key_schedule(const byte key[], size_t) + { + EK.resize(52); + DK.resize(52); + + for(size_t i = 0; i != 8; ++i) + EK[i] = load_be(key, i); + + for(size_t i = 1, j = 8, offset = 0; j != 52; i %= 8, ++i, ++j) + { + EK[i+7+offset] = static_cast((EK[(i % 8) + offset] << 9) | + (EK[((i+1) % 8) + offset] >> 7)); + offset += (i == 8) ? 8 : 0; + } + + DK[51] = mul_inv(EK[3]); + DK[50] = -EK[2]; + DK[49] = -EK[1]; + DK[48] = mul_inv(EK[0]); + + for(size_t i = 1, j = 4, counter = 47; i != 8; ++i, j += 6) + { + DK[counter--] = EK[j+1]; + DK[counter--] = EK[j]; + DK[counter--] = mul_inv(EK[j+5]); + DK[counter--] = -EK[j+3]; + DK[counter--] = -EK[j+4]; + DK[counter--] = mul_inv(EK[j+2]); + } + + DK[5] = EK[47]; + DK[4] = EK[46]; + DK[3] = mul_inv(EK[51]); + DK[2] = -EK[50]; + DK[1] = -EK[49]; + DK[0] = mul_inv(EK[48]); + } + +void IDEA::clear() + { + zap(EK); + zap(DK); + } + +} diff --git a/src/lib/block/idea/idea.h b/src/lib/block/idea/idea.h new file mode 100644 index 000000000..da5dc4cb6 --- /dev/null +++ b/src/lib/block/idea/idea.h @@ -0,0 +1,46 @@ +/* +* IDEA +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_IDEA_H__ +#define BOTAN_IDEA_H__ + +#include + +namespace Botan { + +/** +* IDEA +*/ +class BOTAN_DLL IDEA : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "IDEA"; } + BlockCipher* clone() const { return new IDEA; } + protected: + /** + * @return const reference to encryption subkeys + */ + const secure_vector& get_EK() const { return EK; } + + /** + * @return const reference to decryption subkeys + */ + const secure_vector& get_DK() const { return DK; } + + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +} + +#endif diff --git a/src/lib/block/idea/info.txt b/src/lib/block/idea/info.txt new file mode 100644 index 000000000..dbca72c8d --- /dev/null +++ b/src/lib/block/idea/info.txt @@ -0,0 +1 @@ +define IDEA 20131128 diff --git a/src/lib/block/idea_sse2/idea_sse2.cpp b/src/lib/block/idea_sse2/idea_sse2.cpp new file mode 100644 index 000000000..70698560d --- /dev/null +++ b/src/lib/block/idea_sse2/idea_sse2.cpp @@ -0,0 +1,234 @@ +/* +* IDEA in SSE2 +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +inline __m128i mul(__m128i X, u16bit K_16) + { + const __m128i zeros = _mm_set1_epi16(0); + const __m128i ones = _mm_set1_epi16(1); + + const __m128i K = _mm_set1_epi16(K_16); + + const __m128i X_is_zero = _mm_cmpeq_epi16(X, zeros); + const __m128i K_is_zero = _mm_cmpeq_epi16(K, zeros); + + const __m128i mul_lo = _mm_mullo_epi16(X, K); + const __m128i mul_hi = _mm_mulhi_epu16(X, K); + + __m128i T = _mm_sub_epi16(mul_lo, mul_hi); + + // Unsigned compare; cmp = 1 if mul_lo < mul_hi else 0 + const __m128i subs = _mm_subs_epu16(mul_hi, mul_lo); + const __m128i cmp = _mm_min_epu8( + _mm_or_si128(subs, _mm_srli_epi16(subs, 8)), ones); + + T = _mm_add_epi16(T, cmp); + + /* Selection: if X[i] is zero then assign 1-K + if K is zero then assign 1-X[i] + + Could if() off value of K_16 for the second, but this gives a + constant time implementation which is a nice bonus. + */ + + T = _mm_or_si128( + _mm_andnot_si128(X_is_zero, T), + _mm_and_si128(_mm_sub_epi16(ones, K), X_is_zero)); + + T = _mm_or_si128( + _mm_andnot_si128(K_is_zero, T), + _mm_and_si128(_mm_sub_epi16(ones, X), K_is_zero)); + + return T; + } + +/* +* 4x8 matrix transpose +* +* FIXME: why do I need the extra set of unpack_epi32 here? Inverse in +* transpose_out doesn't need it. Something with the shuffle? Removing +* that extra unpack could easily save 3-4 cycles per block, and would +* also help a lot with register pressure on 32-bit x86 +*/ +void transpose_in(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) + { + __m128i T0 = _mm_unpackhi_epi32(B0, B1); + __m128i T1 = _mm_unpacklo_epi32(B0, B1); + __m128i T2 = _mm_unpackhi_epi32(B2, B3); + __m128i T3 = _mm_unpacklo_epi32(B2, B3); + + __m128i T4 = _mm_unpacklo_epi32(T0, T1); + __m128i T5 = _mm_unpackhi_epi32(T0, T1); + __m128i T6 = _mm_unpacklo_epi32(T2, T3); + __m128i T7 = _mm_unpackhi_epi32(T2, T3); + + T0 = _mm_shufflehi_epi16(T4, _MM_SHUFFLE(1, 3, 0, 2)); + T1 = _mm_shufflehi_epi16(T5, _MM_SHUFFLE(1, 3, 0, 2)); + T2 = _mm_shufflehi_epi16(T6, _MM_SHUFFLE(1, 3, 0, 2)); + T3 = _mm_shufflehi_epi16(T7, _MM_SHUFFLE(1, 3, 0, 2)); + + T0 = _mm_shufflelo_epi16(T0, _MM_SHUFFLE(1, 3, 0, 2)); + T1 = _mm_shufflelo_epi16(T1, _MM_SHUFFLE(1, 3, 0, 2)); + T2 = _mm_shufflelo_epi16(T2, _MM_SHUFFLE(1, 3, 0, 2)); + T3 = _mm_shufflelo_epi16(T3, _MM_SHUFFLE(1, 3, 0, 2)); + + T0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shuffle_epi32(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + B0 = _mm_unpacklo_epi64(T0, T2); + B1 = _mm_unpackhi_epi64(T0, T2); + B2 = _mm_unpacklo_epi64(T1, T3); + B3 = _mm_unpackhi_epi64(T1, T3); + } + +/* +* 4x8 matrix transpose (reverse) +*/ +void transpose_out(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) + { + __m128i T0 = _mm_unpacklo_epi64(B0, B1); + __m128i T1 = _mm_unpacklo_epi64(B2, B3); + __m128i T2 = _mm_unpackhi_epi64(B0, B1); + __m128i T3 = _mm_unpackhi_epi64(B2, B3); + + T0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shuffle_epi32(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + T0 = _mm_shufflehi_epi16(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shufflehi_epi16(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shufflehi_epi16(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shufflehi_epi16(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + T0 = _mm_shufflelo_epi16(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shufflelo_epi16(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shufflelo_epi16(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shufflelo_epi16(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + B0 = _mm_unpacklo_epi32(T0, T1); + B1 = _mm_unpackhi_epi32(T0, T1); + B2 = _mm_unpacklo_epi32(T2, T3); + B3 = _mm_unpackhi_epi32(T2, T3); + } + +/* +* IDEA encryption/decryption in SSE2 +*/ +void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) + { + const __m128i* in_mm = reinterpret_cast(in); + + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + transpose_in(B0, B1, B2, B3); + + // byte swap + B0 = _mm_or_si128(_mm_slli_epi16(B0, 8), _mm_srli_epi16(B0, 8)); + B1 = _mm_or_si128(_mm_slli_epi16(B1, 8), _mm_srli_epi16(B1, 8)); + B2 = _mm_or_si128(_mm_slli_epi16(B2, 8), _mm_srli_epi16(B2, 8)); + B3 = _mm_or_si128(_mm_slli_epi16(B3, 8), _mm_srli_epi16(B3, 8)); + + for(size_t i = 0; i != 8; ++i) + { + B0 = mul(B0, EK[6*i+0]); + B1 = _mm_add_epi16(B1, _mm_set1_epi16(EK[6*i+1])); + B2 = _mm_add_epi16(B2, _mm_set1_epi16(EK[6*i+2])); + B3 = mul(B3, EK[6*i+3]); + + __m128i T0 = B2; + + B2 = _mm_xor_si128(B2, B0); + B2 = mul(B2, EK[6*i+4]); + + __m128i T1 = B1; + + B1 = _mm_xor_si128(B1, B3); + B1 = _mm_add_epi16(B1, B2); + B1 = mul(B1, EK[6*i+5]); + + B2 = _mm_add_epi16(B2, B1); + + B0 = _mm_xor_si128(B0, B1); + B1 = _mm_xor_si128(B1, T0); + B3 = _mm_xor_si128(B3, B2); + B2 = _mm_xor_si128(B2, T1); + } + + B0 = mul(B0, EK[48]); + B1 = _mm_add_epi16(B1, _mm_set1_epi16(EK[50])); + B2 = _mm_add_epi16(B2, _mm_set1_epi16(EK[49])); + B3 = mul(B3, EK[51]); + + // byte swap + B0 = _mm_or_si128(_mm_slli_epi16(B0, 8), _mm_srli_epi16(B0, 8)); + B1 = _mm_or_si128(_mm_slli_epi16(B1, 8), _mm_srli_epi16(B1, 8)); + B2 = _mm_or_si128(_mm_slli_epi16(B2, 8), _mm_srli_epi16(B2, 8)); + B3 = _mm_or_si128(_mm_slli_epi16(B3, 8), _mm_srli_epi16(B3, 8)); + + transpose_out(B0, B2, B1, B3); + + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B2); + _mm_storeu_si128(out_mm + 2, B1); + _mm_storeu_si128(out_mm + 3, B3); + } + +} + +/* +* IDEA Encryption +*/ +void IDEA_SSE2::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u16bit* KS = &this->get_EK()[0]; + + while(blocks >= 8) + { + idea_op_8(in, out, KS); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + + if(blocks) + IDEA::encrypt_n(in, out, blocks); + } + +/* +* IDEA Decryption +*/ +void IDEA_SSE2::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u16bit* KS = &this->get_DK()[0]; + + while(blocks >= 8) + { + idea_op_8(in, out, KS); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + + if(blocks) + IDEA::decrypt_n(in, out, blocks); + } + +} diff --git a/src/lib/block/idea_sse2/idea_sse2.h b/src/lib/block/idea_sse2/idea_sse2.h new file mode 100644 index 000000000..8e475568e --- /dev/null +++ b/src/lib/block/idea_sse2/idea_sse2.h @@ -0,0 +1,31 @@ +/* +* IDEA in SSE2 +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_IDEA_SSE2_H__ +#define BOTAN_IDEA_SSE2_H__ + +#include + +namespace Botan { + +/** +* IDEA in SSE2 +*/ +class BOTAN_DLL IDEA_SSE2 : public IDEA + { + public: + size_t parallelism() const { return 8; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + BlockCipher* clone() const { return new IDEA_SSE2; } + }; + +} + +#endif diff --git a/src/lib/block/idea_sse2/info.txt b/src/lib/block/idea_sse2/info.txt new file mode 100644 index 000000000..cfaaa374a --- /dev/null +++ b/src/lib/block/idea_sse2/info.txt @@ -0,0 +1,7 @@ +define IDEA_SSE2 20131128 + +need_isa sse2 + + +idea + diff --git a/src/lib/block/info.txt b/src/lib/block/info.txt new file mode 100644 index 000000000..70e2b2ca2 --- /dev/null +++ b/src/lib/block/info.txt @@ -0,0 +1,5 @@ +define BLOCK_CIPHER 20131128 + + +algo_base + diff --git a/src/lib/block/kasumi/info.txt b/src/lib/block/kasumi/info.txt new file mode 100644 index 000000000..3dd2a3ac0 --- /dev/null +++ b/src/lib/block/kasumi/info.txt @@ -0,0 +1 @@ +define KASUMI 20131128 diff --git a/src/lib/block/kasumi/kasumi.cpp b/src/lib/block/kasumi/kasumi.cpp new file mode 100644 index 000000000..69f146ebb --- /dev/null +++ b/src/lib/block/kasumi/kasumi.cpp @@ -0,0 +1,234 @@ +/* +* KASUMI +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* KASUMI S-Boxes +*/ +const byte KASUMI_SBOX_S7[128] = { + 0x36, 0x32, 0x3E, 0x38, 0x16, 0x22, 0x5E, 0x60, 0x26, 0x06, 0x3F, 0x5D, + 0x02, 0x12, 0x7B, 0x21, 0x37, 0x71, 0x27, 0x72, 0x15, 0x43, 0x41, 0x0C, + 0x2F, 0x49, 0x2E, 0x1B, 0x19, 0x6F, 0x7C, 0x51, 0x35, 0x09, 0x79, 0x4F, + 0x34, 0x3C, 0x3A, 0x30, 0x65, 0x7F, 0x28, 0x78, 0x68, 0x46, 0x47, 0x2B, + 0x14, 0x7A, 0x48, 0x3D, 0x17, 0x6D, 0x0D, 0x64, 0x4D, 0x01, 0x10, 0x07, + 0x52, 0x0A, 0x69, 0x62, 0x75, 0x74, 0x4C, 0x0B, 0x59, 0x6A, 0x00, 0x7D, + 0x76, 0x63, 0x56, 0x45, 0x1E, 0x39, 0x7E, 0x57, 0x70, 0x33, 0x11, 0x05, + 0x5F, 0x0E, 0x5A, 0x54, 0x5B, 0x08, 0x23, 0x67, 0x20, 0x61, 0x1C, 0x42, + 0x66, 0x1F, 0x1A, 0x2D, 0x4B, 0x04, 0x55, 0x5C, 0x25, 0x4A, 0x50, 0x31, + 0x44, 0x1D, 0x73, 0x2C, 0x40, 0x6B, 0x6C, 0x18, 0x6E, 0x53, 0x24, 0x4E, + 0x2A, 0x13, 0x0F, 0x29, 0x58, 0x77, 0x3B, 0x03 }; + +const u16bit KASUMI_SBOX_S9[512] = { + 0x00A7, 0x00EF, 0x00A1, 0x017B, 0x0187, 0x014E, 0x0009, 0x0152, 0x0026, + 0x00E2, 0x0030, 0x0166, 0x01C4, 0x0181, 0x005A, 0x018D, 0x00B7, 0x00FD, + 0x0093, 0x014B, 0x019F, 0x0154, 0x0033, 0x016A, 0x0132, 0x01F4, 0x0106, + 0x0052, 0x00D8, 0x009F, 0x0164, 0x00B1, 0x00AF, 0x00F1, 0x01E9, 0x0025, + 0x00CE, 0x0011, 0x0000, 0x014D, 0x002C, 0x00FE, 0x017A, 0x003A, 0x008F, + 0x00DC, 0x0051, 0x0190, 0x005F, 0x0003, 0x013B, 0x00F5, 0x0036, 0x00EB, + 0x00DA, 0x0195, 0x01D8, 0x0108, 0x00AC, 0x01EE, 0x0173, 0x0122, 0x018F, + 0x004C, 0x00A5, 0x00C5, 0x018B, 0x0079, 0x0101, 0x01E0, 0x01A7, 0x00D4, + 0x00F0, 0x001C, 0x01CE, 0x00B0, 0x0196, 0x01FB, 0x0120, 0x00DF, 0x01F5, + 0x0197, 0x00F9, 0x0109, 0x0059, 0x00BA, 0x00DD, 0x01AC, 0x00A4, 0x004A, + 0x01B8, 0x00C4, 0x01CA, 0x01A5, 0x015E, 0x00A3, 0x00E8, 0x009E, 0x0086, + 0x0162, 0x000D, 0x00FA, 0x01EB, 0x008E, 0x00BF, 0x0045, 0x00C1, 0x01A9, + 0x0098, 0x00E3, 0x016E, 0x0087, 0x0158, 0x012C, 0x0114, 0x00F2, 0x01B5, + 0x0140, 0x0071, 0x0116, 0x000B, 0x00F3, 0x0057, 0x013D, 0x0024, 0x005D, + 0x01F0, 0x001B, 0x01E7, 0x01BE, 0x01E2, 0x0029, 0x0044, 0x009C, 0x01C9, + 0x0083, 0x0146, 0x0193, 0x0153, 0x0014, 0x0027, 0x0073, 0x01BA, 0x007C, + 0x01DB, 0x0180, 0x01FC, 0x0035, 0x0070, 0x00AA, 0x01DF, 0x0097, 0x007E, + 0x00A9, 0x0049, 0x010C, 0x0117, 0x0141, 0x00A8, 0x016C, 0x016B, 0x0124, + 0x002E, 0x01F3, 0x0189, 0x0147, 0x0144, 0x0018, 0x01C8, 0x010B, 0x009D, + 0x01CC, 0x01E8, 0x01AA, 0x0135, 0x00E5, 0x01B7, 0x01FA, 0x00D0, 0x010F, + 0x015D, 0x0191, 0x01B2, 0x00EC, 0x0010, 0x00D1, 0x0167, 0x0034, 0x0038, + 0x0078, 0x00C7, 0x0115, 0x01D1, 0x01A0, 0x00FC, 0x011F, 0x00F6, 0x0006, + 0x0053, 0x0131, 0x01A4, 0x0159, 0x0099, 0x01F6, 0x0041, 0x003D, 0x00F4, + 0x011A, 0x00AD, 0x00DE, 0x01A2, 0x0043, 0x0182, 0x0170, 0x0105, 0x0065, + 0x01DC, 0x0123, 0x00C3, 0x01AE, 0x0031, 0x004F, 0x00A6, 0x014A, 0x0118, + 0x017F, 0x0175, 0x0080, 0x017E, 0x0198, 0x009B, 0x01EF, 0x016F, 0x0184, + 0x0112, 0x006B, 0x01CB, 0x01A1, 0x003E, 0x01C6, 0x0084, 0x00E1, 0x00CB, + 0x013C, 0x00EA, 0x000E, 0x012D, 0x005B, 0x01F7, 0x011E, 0x01A8, 0x00D3, + 0x015B, 0x0133, 0x008C, 0x0176, 0x0023, 0x0067, 0x007D, 0x01AB, 0x0013, + 0x00D6, 0x01C5, 0x0092, 0x01F2, 0x013A, 0x01BC, 0x00E6, 0x0100, 0x0149, + 0x00C6, 0x011D, 0x0032, 0x0074, 0x004E, 0x019A, 0x000A, 0x00CD, 0x01FE, + 0x00AB, 0x00E7, 0x002D, 0x008B, 0x01D3, 0x001D, 0x0056, 0x01F9, 0x0020, + 0x0048, 0x001A, 0x0156, 0x0096, 0x0139, 0x01EA, 0x01AF, 0x00EE, 0x019B, + 0x0145, 0x0095, 0x01D9, 0x0028, 0x0077, 0x00AE, 0x0163, 0x00B9, 0x00E9, + 0x0185, 0x0047, 0x01C0, 0x0111, 0x0174, 0x0037, 0x006E, 0x00B2, 0x0142, + 0x000C, 0x01D5, 0x0188, 0x0171, 0x00BE, 0x0001, 0x006D, 0x0177, 0x0089, + 0x00B5, 0x0058, 0x004B, 0x0134, 0x0104, 0x01E4, 0x0062, 0x0110, 0x0172, + 0x0113, 0x019C, 0x006F, 0x0150, 0x013E, 0x0004, 0x01F8, 0x01EC, 0x0103, + 0x0130, 0x004D, 0x0151, 0x01B3, 0x0015, 0x0165, 0x012F, 0x014C, 0x01E3, + 0x0012, 0x002F, 0x0055, 0x0019, 0x01F1, 0x01DA, 0x0121, 0x0064, 0x010D, + 0x0128, 0x01DE, 0x010E, 0x006A, 0x001F, 0x0068, 0x01B1, 0x0054, 0x019E, + 0x01E6, 0x018A, 0x0060, 0x0063, 0x009A, 0x01FF, 0x0094, 0x019D, 0x0169, + 0x0199, 0x00FF, 0x00A2, 0x00D7, 0x012E, 0x00C9, 0x010A, 0x015F, 0x0157, + 0x0090, 0x01B9, 0x016D, 0x006C, 0x012A, 0x00FB, 0x0022, 0x00B6, 0x01FD, + 0x008A, 0x00D2, 0x014F, 0x0085, 0x0137, 0x0160, 0x0148, 0x008D, 0x018C, + 0x015A, 0x007B, 0x013F, 0x01C2, 0x0119, 0x01AD, 0x00E4, 0x01BB, 0x01E1, + 0x005C, 0x0194, 0x01E5, 0x01A6, 0x00F8, 0x0129, 0x0017, 0x00D5, 0x0082, + 0x01D2, 0x0016, 0x00D9, 0x011B, 0x0046, 0x0126, 0x0168, 0x01A3, 0x007F, + 0x0138, 0x0179, 0x0007, 0x01D4, 0x00C2, 0x0002, 0x0075, 0x0127, 0x01CF, + 0x0102, 0x00E0, 0x01BF, 0x00F7, 0x00BB, 0x0050, 0x018E, 0x011C, 0x0161, + 0x0069, 0x0186, 0x012B, 0x01D7, 0x01D6, 0x00B8, 0x0039, 0x00C8, 0x015C, + 0x003F, 0x00CC, 0x00BC, 0x0021, 0x01C3, 0x0061, 0x001E, 0x0136, 0x00DB, + 0x005E, 0x00A0, 0x0081, 0x01ED, 0x0040, 0x00B3, 0x0107, 0x0066, 0x00BD, + 0x00CF, 0x0072, 0x0192, 0x01B6, 0x01DD, 0x0183, 0x007A, 0x00C0, 0x002A, + 0x017D, 0x0005, 0x0091, 0x0076, 0x00B4, 0x01C1, 0x0125, 0x0143, 0x0088, + 0x017C, 0x002B, 0x0042, 0x003C, 0x01C7, 0x0155, 0x01BD, 0x00CA, 0x01B0, + 0x0008, 0x00ED, 0x000F, 0x0178, 0x01B4, 0x01D0, 0x003B, 0x01CD }; + +/* +* KASUMI FI Function +*/ +u16bit FI(u16bit I, u16bit K) + { + u16bit D9 = (I >> 7); + byte D7 = (I & 0x7F); + D9 = KASUMI_SBOX_S9[D9] ^ D7; + D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); + + D7 ^= (K >> 9); + D9 = KASUMI_SBOX_S9[D9 ^ (K & 0x1FF)] ^ D7; + D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); + return (D7 << 9) | D9; + } + +} + +/* +* KASUMI Encryption +*/ +void KASUMI::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 0); + u16bit B1 = load_be(in, 1); + u16bit B2 = load_be(in, 2); + u16bit B3 = load_be(in, 3); + + for(size_t j = 0; j != 8; j += 2) + { + const u16bit* K = &EK[8*j]; + + u16bit R = B1 ^ (rotate_left(B0, 1) & K[0]); + u16bit L = B0 ^ (rotate_left(R, 1) | K[1]); + + L = FI(L ^ K[ 2], K[ 3]) ^ R; + R = FI(R ^ K[ 4], K[ 5]) ^ L; + L = FI(L ^ K[ 6], K[ 7]) ^ R; + + R = B2 ^= R; + L = B3 ^= L; + + R = FI(R ^ K[10], K[11]) ^ L; + L = FI(L ^ K[12], K[13]) ^ R; + R = FI(R ^ K[14], K[15]) ^ L; + + R ^= (rotate_left(L, 1) & K[8]); + L ^= (rotate_left(R, 1) | K[9]); + + B0 ^= L; + B1 ^= R; + } + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* KASUMI Decryption +*/ +void KASUMI::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 0); + u16bit B1 = load_be(in, 1); + u16bit B2 = load_be(in, 2); + u16bit B3 = load_be(in, 3); + + for(size_t j = 0; j != 8; j += 2) + { + const u16bit* K = &EK[8*(6-j)]; + + u16bit L = B2, R = B3; + + L = FI(L ^ K[10], K[11]) ^ R; + R = FI(R ^ K[12], K[13]) ^ L; + L = FI(L ^ K[14], K[15]) ^ R; + + L ^= (rotate_left(R, 1) & K[8]); + R ^= (rotate_left(L, 1) | K[9]); + + R = B0 ^= R; + L = B1 ^= L; + + L ^= (rotate_left(R, 1) & K[0]); + R ^= (rotate_left(L, 1) | K[1]); + + R = FI(R ^ K[2], K[3]) ^ L; + L = FI(L ^ K[4], K[5]) ^ R; + R = FI(R ^ K[6], K[7]) ^ L; + + B2 ^= L; + B3 ^= R; + } + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* KASUMI Key Schedule +*/ +void KASUMI::key_schedule(const byte key[], size_t) + { + static const u16bit RC[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, + 0xFEDC, 0xBA98, 0x7654, 0x3210 }; + + secure_vector K(16); + for(size_t i = 0; i != 8; ++i) + { + K[i] = load_be(key, i); + K[i+8] = K[i] ^ RC[i]; + } + + EK.resize(64); + + for(size_t i = 0; i != 8; ++i) + { + EK[8*i ] = rotate_left(K[(i+0) % 8 ], 2); + EK[8*i+1] = rotate_left(K[(i+2) % 8 + 8], 1); + EK[8*i+2] = rotate_left(K[(i+1) % 8 ], 5); + EK[8*i+3] = K[(i+4) % 8 + 8]; + EK[8*i+4] = rotate_left(K[(i+5) % 8 ], 8); + EK[8*i+5] = K[(i+3) % 8 + 8]; + EK[8*i+6] = rotate_left(K[(i+6) % 8 ], 13); + EK[8*i+7] = K[(i+7) % 8 + 8]; + } + } + +void KASUMI::clear() + { + zap(EK); + } + +} diff --git a/src/lib/block/kasumi/kasumi.h b/src/lib/block/kasumi/kasumi.h new file mode 100644 index 000000000..b91a2eb77 --- /dev/null +++ b/src/lib/block/kasumi/kasumi.h @@ -0,0 +1,35 @@ +/* +* KASUMI +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KASUMI_H__ +#define BOTAN_KASUMI_H__ + +#include + +namespace Botan { + +/** +* KASUMI, the block cipher used in 3G telephony +*/ +class BOTAN_DLL KASUMI : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "KASUMI"; } + BlockCipher* clone() const { return new KASUMI; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK; + }; + +} + +#endif diff --git a/src/lib/block/lion/info.txt b/src/lib/block/lion/info.txt new file mode 100644 index 000000000..c775ff428 --- /dev/null +++ b/src/lib/block/lion/info.txt @@ -0,0 +1,6 @@ +define LION 20131128 + + +hash +stream + diff --git a/src/lib/block/lion/lion.cpp b/src/lib/block/lion/lion.cpp new file mode 100644 index 000000000..e1e0b56c6 --- /dev/null +++ b/src/lib/block/lion/lion.cpp @@ -0,0 +1,129 @@ +/* +* Lion +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Lion Encryption +*/ +void Lion::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + secure_vector buffer_vec(LEFT_SIZE); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(buffer, in, &key1[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); + + hash->update(out + LEFT_SIZE, RIGHT_SIZE); + hash->final(buffer); + xor_buf(out, in, buffer, LEFT_SIZE); + + xor_buf(buffer, out, &key2[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Lion Decryption +*/ +void Lion::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + secure_vector buffer_vec(LEFT_SIZE); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(buffer, in, &key2[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); + + hash->update(out + LEFT_SIZE, RIGHT_SIZE); + hash->final(buffer); + xor_buf(out, in, buffer, LEFT_SIZE); + + xor_buf(buffer, out, &key1[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Lion Key Schedule +*/ +void Lion::key_schedule(const byte key[], size_t length) + { + clear(); + + const size_t half = length / 2; + copy_mem(&key1[0], key, half); + copy_mem(&key2[0], key + half, half); + } + +/* +* Return the name of this type +*/ +std::string Lion::name() const + { + return "Lion(" + hash->name() + "," + + cipher->name() + "," + + std::to_string(BLOCK_SIZE) + ")"; + } + +/* +* Return a clone of this object +*/ +BlockCipher* Lion::clone() const + { + return new Lion(hash->clone(), cipher->clone(), BLOCK_SIZE); + } + +/* +* Clear memory of sensitive data +*/ +void Lion::clear() + { + zeroise(key1); + zeroise(key2); + hash->clear(); + cipher->clear(); + } + +/* +* Lion Constructor +*/ +Lion::Lion(HashFunction* hash_in, StreamCipher* sc_in, size_t block_len) : + BLOCK_SIZE(std::max(2*hash_in->output_length() + 1, block_len)), + LEFT_SIZE(hash_in->output_length()), + RIGHT_SIZE(BLOCK_SIZE - LEFT_SIZE), + hash(hash_in), + cipher(sc_in) + { + if(2*LEFT_SIZE + 1 > BLOCK_SIZE) + throw Invalid_Argument(name() + ": Chosen block size is too small"); + + if(!cipher->valid_keylength(LEFT_SIZE)) + throw Invalid_Argument(name() + ": This stream/hash combo is invalid"); + + key1.resize(LEFT_SIZE); + key2.resize(LEFT_SIZE); + } + +} diff --git a/src/lib/block/lion/lion.h b/src/lib/block/lion/lion.h new file mode 100644 index 000000000..37aad19f2 --- /dev/null +++ b/src/lib/block/lion/lion.h @@ -0,0 +1,67 @@ +/* +* Lion +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LION_H__ +#define BOTAN_LION_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Lion is a block cipher construction designed by Ross Anderson and +* Eli Biham, described in "Two Practical and Provably Secure Block +* Ciphers: BEAR and LION". It has a variable block size and is +* designed to encrypt very large blocks (up to a megabyte) + +* http://www.cl.cam.ac.uk/~rja14/Papers/bear-lion.pdf +*/ +class BOTAN_DLL Lion : public BlockCipher + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + size_t block_size() const { return BLOCK_SIZE; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(2, 2*hash->output_length(), 2); + } + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * @param hash the hash to use internally + * @param cipher the stream cipher to use internally + * @param block_size the size of the block to use + */ + Lion(HashFunction* hash, + StreamCipher* cipher, + size_t block_size); + + Lion(const Lion&) = delete; + Lion& operator=(const Lion&) = delete; + + ~Lion() { delete hash; delete cipher; } + private: + void key_schedule(const byte[], size_t); + + const size_t BLOCK_SIZE, LEFT_SIZE, RIGHT_SIZE; + + HashFunction* hash; + StreamCipher* cipher; + secure_vector key1, key2; + }; + +} + +#endif diff --git a/src/lib/block/lubyrack/info.txt b/src/lib/block/lubyrack/info.txt new file mode 100644 index 000000000..1d83a0bac --- /dev/null +++ b/src/lib/block/lubyrack/info.txt @@ -0,0 +1,5 @@ +define LUBY_RACKOFF 20131128 + + +hash + diff --git a/src/lib/block/lubyrack/lubyrack.cpp b/src/lib/block/lubyrack/lubyrack.cpp new file mode 100644 index 000000000..9be079003 --- /dev/null +++ b/src/lib/block/lubyrack/lubyrack.cpp @@ -0,0 +1,129 @@ +/* +* Luby-Rackoff +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Luby-Rackoff Encryption +*/ +void LubyRackoff::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t len = hash->output_length(); + + secure_vector buffer_vec(len); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + hash->update(K1); + hash->update(in, len); + hash->final(buffer); + xor_buf(out + len, in + len, buffer, len); + + hash->update(K2); + hash->update(out + len, len); + hash->final(buffer); + xor_buf(out, in, buffer, len); + + hash->update(K1); + hash->update(out, len); + hash->final(buffer); + xor_buf(out + len, buffer, len); + + hash->update(K2); + hash->update(out + len, len); + hash->final(buffer); + xor_buf(out, buffer, len); + + in += 2 * len; + out += 2 * len; + } + } + +/* +* Luby-Rackoff Decryption +*/ +void LubyRackoff::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t len = hash->output_length(); + + secure_vector buffer_vec(len); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + hash->update(K2); + hash->update(in + len, len); + hash->final(buffer); + xor_buf(out, in, buffer, len); + + hash->update(K1); + hash->update(out, len); + hash->final(buffer); + xor_buf(out + len, in + len, buffer, len); + + hash->update(K2); + hash->update(out + len, len); + hash->final(buffer); + xor_buf(out, buffer, len); + + hash->update(K1); + hash->update(out, len); + hash->final(buffer); + xor_buf(out + len, buffer, len); + + in += 2 * len; + out += 2 * len; + } + } + +/* +* Luby-Rackoff Key Schedule +*/ +void LubyRackoff::key_schedule(const byte key[], size_t length) + { + K1.assign(key, key + (length / 2)); + K2.assign(key + (length / 2), key + length); + } + +/* +* Clear memory of sensitive data +*/ +void LubyRackoff::clear() + { + zap(K1); + zap(K2); + hash->clear(); + } + +/* +* Return a clone of this object +*/ +BlockCipher* LubyRackoff::clone() const + { + return new LubyRackoff(hash->clone()); + } + +/* +* Return the name of this type +*/ +std::string LubyRackoff::name() const + { + return "Luby-Rackoff(" + hash->name() + ")"; + } + +/* +* Luby-Rackoff Constructor +*/ +LubyRackoff::LubyRackoff(HashFunction* h) : hash(h) + { + } + +} diff --git a/src/lib/block/lubyrack/lubyrack.h b/src/lib/block/lubyrack/lubyrack.h new file mode 100644 index 000000000..e28c60be7 --- /dev/null +++ b/src/lib/block/lubyrack/lubyrack.h @@ -0,0 +1,50 @@ +/* +* Luby-Rackoff +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LUBY_RACKOFF_H__ +#define BOTAN_LUBY_RACKOFF_H__ + +#include +#include + +namespace Botan { + +/** +* Luby-Rackoff block cipher construction +*/ +class BOTAN_DLL LubyRackoff : public BlockCipher + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + size_t block_size() const { return 2 * hash->output_length(); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(2, 32, 2); + } + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * @param hash function to use to form the block cipher + */ + LubyRackoff(HashFunction* hash); + ~LubyRackoff() { delete hash; } + private: + void key_schedule(const byte[], size_t); + + HashFunction* hash; + secure_vector K1, K2; + }; + +} + +#endif diff --git a/src/lib/block/mars/info.txt b/src/lib/block/mars/info.txt new file mode 100644 index 000000000..0af3d7955 --- /dev/null +++ b/src/lib/block/mars/info.txt @@ -0,0 +1 @@ +define MARS 20131128 diff --git a/src/lib/block/mars/mars.cpp b/src/lib/block/mars/mars.cpp new file mode 100644 index 000000000..ca4e6f5c7 --- /dev/null +++ b/src/lib/block/mars/mars.cpp @@ -0,0 +1,393 @@ +/* +* MARS +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/** +* The MARS sbox +*/ +const u32bit SBOX[512] = { + 0x09D0C479, 0x28C8FFE0, 0x84AA6C39, 0x9DAD7287, 0x7DFF9BE3, 0xD4268361, + 0xC96DA1D4, 0x7974CC93, 0x85D0582E, 0x2A4B5705, 0x1CA16A62, 0xC3BD279D, + 0x0F1F25E5, 0x5160372F, 0xC695C1FB, 0x4D7FF1E4, 0xAE5F6BF4, 0x0D72EE46, + 0xFF23DE8A, 0xB1CF8E83, 0xF14902E2, 0x3E981E42, 0x8BF53EB6, 0x7F4BF8AC, + 0x83631F83, 0x25970205, 0x76AFE784, 0x3A7931D4, 0x4F846450, 0x5C64C3F6, + 0x210A5F18, 0xC6986A26, 0x28F4E826, 0x3A60A81C, 0xD340A664, 0x7EA820C4, + 0x526687C5, 0x7EDDD12B, 0x32A11D1D, 0x9C9EF086, 0x80F6E831, 0xAB6F04AD, + 0x56FB9B53, 0x8B2E095C, 0xB68556AE, 0xD2250B0D, 0x294A7721, 0xE21FB253, + 0xAE136749, 0xE82AAE86, 0x93365104, 0x99404A66, 0x78A784DC, 0xB69BA84B, + 0x04046793, 0x23DB5C1E, 0x46CAE1D6, 0x2FE28134, 0x5A223942, 0x1863CD5B, + 0xC190C6E3, 0x07DFB846, 0x6EB88816, 0x2D0DCC4A, 0xA4CCAE59, 0x3798670D, + 0xCBFA9493, 0x4F481D45, 0xEAFC8CA8, 0xDB1129D6, 0xB0449E20, 0x0F5407FB, + 0x6167D9A8, 0xD1F45763, 0x4DAA96C3, 0x3BEC5958, 0xABABA014, 0xB6CCD201, + 0x38D6279F, 0x02682215, 0x8F376CD5, 0x092C237E, 0xBFC56593, 0x32889D2C, + 0x854B3E95, 0x05BB9B43, 0x7DCD5DCD, 0xA02E926C, 0xFAE527E5, 0x36A1C330, + 0x3412E1AE, 0xF257F462, 0x3C4F1D71, 0x30A2E809, 0x68E5F551, 0x9C61BA44, + 0x5DED0AB8, 0x75CE09C8, 0x9654F93E, 0x698C0CCA, 0x243CB3E4, 0x2B062B97, + 0x0F3B8D9E, 0x00E050DF, 0xFC5D6166, 0xE35F9288, 0xC079550D, 0x0591AEE8, + 0x8E531E74, 0x75FE3578, 0x2F6D829A, 0xF60B21AE, 0x95E8EB8D, 0x6699486B, + 0x901D7D9B, 0xFD6D6E31, 0x1090ACEF, 0xE0670DD8, 0xDAB2E692, 0xCD6D4365, + 0xE5393514, 0x3AF345F0, 0x6241FC4D, 0x460DA3A3, 0x7BCF3729, 0x8BF1D1E0, + 0x14AAC070, 0x1587ED55, 0x3AFD7D3E, 0xD2F29E01, 0x29A9D1F6, 0xEFB10C53, + 0xCF3B870F, 0xB414935C, 0x664465ED, 0x024ACAC7, 0x59A744C1, 0x1D2936A7, + 0xDC580AA6, 0xCF574CA8, 0x040A7A10, 0x6CD81807, 0x8A98BE4C, 0xACCEA063, + 0xC33E92B5, 0xD1E0E03D, 0xB322517E, 0x2092BD13, 0x386B2C4A, 0x52E8DD58, + 0x58656DFB, 0x50820371, 0x41811896, 0xE337EF7E, 0xD39FB119, 0xC97F0DF6, + 0x68FEA01B, 0xA150A6E5, 0x55258962, 0xEB6FF41B, 0xD7C9CD7A, 0xA619CD9E, + 0xBCF09576, 0x2672C073, 0xF003FB3C, 0x4AB7A50B, 0x1484126A, 0x487BA9B1, + 0xA64FC9C6, 0xF6957D49, 0x38B06A75, 0xDD805FCD, 0x63D094CF, 0xF51C999E, + 0x1AA4D343, 0xB8495294, 0xCE9F8E99, 0xBFFCD770, 0xC7C275CC, 0x378453A7, + 0x7B21BE33, 0x397F41BD, 0x4E94D131, 0x92CC1F98, 0x5915EA51, 0x99F861B7, + 0xC9980A88, 0x1D74FD5F, 0xB0A495F8, 0x614DEED0, 0xB5778EEA, 0x5941792D, + 0xFA90C1F8, 0x33F824B4, 0xC4965372, 0x3FF6D550, 0x4CA5FEC0, 0x8630E964, + 0x5B3FBBD6, 0x7DA26A48, 0xB203231A, 0x04297514, 0x2D639306, 0x2EB13149, + 0x16A45272, 0x532459A0, 0x8E5F4872, 0xF966C7D9, 0x07128DC0, 0x0D44DB62, + 0xAFC8D52D, 0x06316131, 0xD838E7CE, 0x1BC41D00, 0x3A2E8C0F, 0xEA83837E, + 0xB984737D, 0x13BA4891, 0xC4F8B949, 0xA6D6ACB3, 0xA215CDCE, 0x8359838B, + 0x6BD1AA31, 0xF579DD52, 0x21B93F93, 0xF5176781, 0x187DFDDE, 0xE94AEB76, + 0x2B38FD54, 0x431DE1DA, 0xAB394825, 0x9AD3048F, 0xDFEA32AA, 0x659473E3, + 0x623F7863, 0xF3346C59, 0xAB3AB685, 0x3346A90B, 0x6B56443E, 0xC6DE01F8, + 0x8D421FC0, 0x9B0ED10C, 0x88F1A1E9, 0x54C1F029, 0x7DEAD57B, 0x8D7BA426, + 0x4CF5178A, 0x551A7CCA, 0x1A9A5F08, 0xFCD651B9, 0x25605182, 0xE11FC6C3, + 0xB6FD9676, 0x337B3027, 0xB7C8EB14, 0x9E5FD030, 0x6B57E354, 0xAD913CF7, + 0x7E16688D, 0x58872A69, 0x2C2FC7DF, 0xE389CCC6, 0x30738DF1, 0x0824A734, + 0xE1797A8B, 0xA4A8D57B, 0x5B5D193B, 0xC8A8309B, 0x73F9A978, 0x73398D32, + 0x0F59573E, 0xE9DF2B03, 0xE8A5B6C8, 0x848D0704, 0x98DF93C2, 0x720A1DC3, + 0x684F259A, 0x943BA848, 0xA6370152, 0x863B5EA3, 0xD17B978B, 0x6D9B58EF, + 0x0A700DD4, 0xA73D36BF, 0x8E6A0829, 0x8695BC14, 0xE35B3447, 0x933AC568, + 0x8894B022, 0x2F511C27, 0xDDFBCC3C, 0x006662B6, 0x117C83FE, 0x4E12B414, + 0xC2BCA766, 0x3A2FEC10, 0xF4562420, 0x55792E2A, 0x46F5D857, 0xCEDA25CE, + 0xC3601D3B, 0x6C00AB46, 0xEFAC9C28, 0xB3C35047, 0x611DFEE3, 0x257C3207, + 0xFDD58482, 0x3B14D84F, 0x23BECB64, 0xA075F3A3, 0x088F8EAD, 0x07ADF158, + 0x7796943C, 0xFACABF3D, 0xC09730CD, 0xF7679969, 0xDA44E9ED, 0x2C854C12, + 0x35935FA3, 0x2F057D9F, 0x690624F8, 0x1CB0BAFD, 0x7B0DBDC6, 0x810F23BB, + 0xFA929A1A, 0x6D969A17, 0x6742979B, 0x74AC7D05, 0x010E65C4, 0x86A3D963, + 0xF907B5A0, 0xD0042BD3, 0x158D7D03, 0x287A8255, 0xBBA8366F, 0x096EDC33, + 0x21916A7B, 0x77B56B86, 0x951622F9, 0xA6C5E650, 0x8CEA17D1, 0xCD8C62BC, + 0xA3D63433, 0x358A68FD, 0x0F9B9D3C, 0xD6AA295B, 0xFE33384A, 0xC000738E, + 0xCD67EB2F, 0xE2EB6DC2, 0x97338B02, 0x06C9F246, 0x419CF1AD, 0x2B83C045, + 0x3723F18A, 0xCB5B3089, 0x160BEAD7, 0x5D494656, 0x35F8A74B, 0x1E4E6C9E, + 0x000399BD, 0x67466880, 0xB4174831, 0xACF423B2, 0xCA815AB3, 0x5A6395E7, + 0x302A67C5, 0x8BDB446B, 0x108F8FA4, 0x10223EDA, 0x92B8B48B, 0x7F38D0EE, + 0xAB2701D4, 0x0262D415, 0xAF224A30, 0xB3D88ABA, 0xF8B2C3AF, 0xDAF7EF70, + 0xCC97D3B7, 0xE9614B6C, 0x2BAEBFF4, 0x70F687CF, 0x386C9156, 0xCE092EE5, + 0x01E87DA6, 0x6CE91E6A, 0xBB7BCC84, 0xC7922C20, 0x9D3B71FD, 0x060E41C6, + 0xD7590F15, 0x4E03BB47, 0x183C198E, 0x63EEB240, 0x2DDBF49A, 0x6D5CBA54, + 0x923750AF, 0xF9E14236, 0x7838162B, 0x59726C72, 0x81B66760, 0xBB2926C1, + 0x48A0CE0D, 0xA6C0496D, 0xAD43507B, 0x718D496A, 0x9DF057AF, 0x44B1BDE6, + 0x054356DC, 0xDE7CED35, 0xD51A138B, 0x62088CC9, 0x35830311, 0xC96EFCA2, + 0x686F86EC, 0x8E77CB68, 0x63E1D6B8, 0xC80F9778, 0x79C491FD, 0x1B4C67F2, + 0x72698D7D, 0x5E368C31, 0xF7D95E2E, 0xA1D3493F, 0xDCD9433E, 0x896F1552, + 0x4BC4CA7A, 0xA6D1BAF4, 0xA5A96DCC, 0x0BEF8B46, 0xA169FDA7, 0x74DF40B7, + 0x4E208804, 0x9A756607, 0x038E87C8, 0x20211E44, 0x8B7AD4BF, 0xC6403F35, + 0x1848E36D, 0x80BDB038, 0x1E62891C, 0x643D2107, 0xBF04D6F8, 0x21092C8C, + 0xF644F389, 0x0778404E, 0x7B78ADB8, 0xA2C52D53, 0x42157ABE, 0xA2253E2E, + 0x7BF3F4AE, 0x80F594F9, 0x953194E7, 0x77EB92ED, 0xB3816930, 0xDA8D9336, + 0xBF447469, 0xF26D9483, 0xEE6FAED5, 0x71371235, 0xDE425F73, 0xB4E59F43, + 0x7DBE2D4E, 0x2D37B185, 0x49DC9A63, 0x98C39D98, 0x1301C9A2, 0x389B1BBF, + 0x0C18588D, 0xA421C1BA, 0x7AA3865C, 0x71E08558, 0x3C5CFCAA, 0x7D239CA4, + 0x0297D9DD, 0xD7DC2830, 0x4B37802B, 0x7428AB54, 0xAEEE0347, 0x4B3FBB85, + 0x692F2F08, 0x134E578E, 0x36D9E0BF, 0xAE8B5FCF, 0xEDB93ECF, 0x2B27248E, + 0x170EB1EF, 0x7DC57FD6, 0x1E760F16, 0xB1136601, 0x864E1B9B, 0xD7EA7319, + 0x3AB871BD, 0xCFA4D76F, 0xE31BD782, 0x0DBEB469, 0xABB96061, 0x5370F85D, + 0xFFB07E37, 0xDA30D0FB, 0xEBC977B6, 0x0B98B40F, 0x3A4D0FE6, 0xDF4FC26B, + 0x159CF22A, 0xC298D6E2, 0x2B78EF6A, 0x61A94AC0, 0xAB561187, 0x14EEA0F0, + 0xDF0D4164, 0x19AF70EE }; + +/* +* MARS Encryption Round +*/ +inline void encrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D, + u32bit EK1, u32bit EK2) + { + const u32bit X = A + EK1; + A = rotate_left(A, 13); + u32bit Y = A * EK2; + u32bit Z = SBOX[X % 512]; + + Y = rotate_left(Y, 5); + Z ^= Y; + C += rotate_left(X, Y % 32); + Y = rotate_left(Y, 5); + Z ^= Y; + D ^= Y; + B += rotate_left(Z, Y % 32); + } + +/* +* MARS Decryption Round +*/ +inline void decrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D, + u32bit EK1, u32bit EK2) + { + u32bit Y = A * EK1; + A = rotate_right(A, 13); + const u32bit X = A + EK2; + u32bit Z = SBOX[X % 512]; + + Y = rotate_left(Y, 5); + Z ^= Y; + C -= rotate_left(X, Y % 32); + Y = rotate_left(Y, 5); + Z ^= Y; + D ^= Y; + B -= rotate_left(Z, Y % 32); + } + +/* +* MARS Forward Mixing Operation +*/ +void forward_mix(u32bit& A, u32bit& B, u32bit& C, u32bit& D) + { + for(size_t j = 0; j != 2; ++j) + { + B ^= SBOX[get_byte(3, A)]; B += SBOX[get_byte(2, A) + 256]; + C += SBOX[get_byte(1, A)]; D ^= SBOX[get_byte(0, A) + 256]; + A = rotate_right(A, 24) + D; + + C ^= SBOX[get_byte(3, B)]; C += SBOX[get_byte(2, B) + 256]; + D += SBOX[get_byte(1, B)]; A ^= SBOX[get_byte(0, B) + 256]; + B = rotate_right(B, 24) + C; + + D ^= SBOX[get_byte(3, C)]; D += SBOX[get_byte(2, C) + 256]; + A += SBOX[get_byte(1, C)]; B ^= SBOX[get_byte(0, C) + 256]; + C = rotate_right(C, 24); + + A ^= SBOX[get_byte(3, D)]; A += SBOX[get_byte(2, D) + 256]; + B += SBOX[get_byte(1, D)]; C ^= SBOX[get_byte(0, D) + 256]; + D = rotate_right(D, 24); + } + } + +/* +* MARS Reverse Mixing Operation +*/ +void reverse_mix(u32bit& A, u32bit& B, u32bit& C, u32bit& D) + { + for(size_t j = 0; j != 2; ++j) + { + B ^= SBOX[get_byte(3, A) + 256]; C -= SBOX[get_byte(0, A)]; + D -= SBOX[get_byte(1, A) + 256]; D ^= SBOX[get_byte(2, A)]; + A = rotate_left(A, 24); + + C ^= SBOX[get_byte(3, B) + 256]; D -= SBOX[get_byte(0, B)]; + A -= SBOX[get_byte(1, B) + 256]; A ^= SBOX[get_byte(2, B)]; + C -= (B = rotate_left(B, 24)); + + D ^= SBOX[get_byte(3, C) + 256]; A -= SBOX[get_byte(0, C)]; + B -= SBOX[get_byte(1, C) + 256]; B ^= SBOX[get_byte(2, C)]; + C = rotate_left(C, 24); + D -= A; + + A ^= SBOX[get_byte(3, D) + 256]; B -= SBOX[get_byte(0, D)]; + C -= SBOX[get_byte(1, D) + 256]; C ^= SBOX[get_byte(2, D)]; + D = rotate_left(D, 24); + } + } + +/* +* Generate a mask for runs of bits +*/ +u32bit gen_mask(u32bit input) + { + u32bit mask = 0; + + for(u32bit j = 2; j != 31; ++j) + { + const u32bit region = (input >> (j-1)) & 0x07; + + if(region == 0x00 || region == 0x07) + { + const u32bit low = (j < 9) ? 0 : (j - 9); + const u32bit high = (j < 23) ? j : 23; + + for(u32bit k = low; k != high; ++k) + { + const u32bit value = (input >> k) & 0x3FF; + + if(value == 0 || value == 0x3FF) + { + mask |= 1 << j; + break; + } + } + } + } + + return mask; + } + +} + +/* +* MARS Encryption +*/ +void MARS::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0) + EK[0]; + u32bit B = load_le(in, 1) + EK[1]; + u32bit C = load_le(in, 2) + EK[2]; + u32bit D = load_le(in, 3) + EK[3]; + + forward_mix(A, B, C, D); + + encrypt_round(A, B, C, D, EK[ 4], EK[ 5]); + encrypt_round(B, C, D, A, EK[ 6], EK[ 7]); + encrypt_round(C, D, A, B, EK[ 8], EK[ 9]); + encrypt_round(D, A, B, C, EK[10], EK[11]); + encrypt_round(A, B, C, D, EK[12], EK[13]); + encrypt_round(B, C, D, A, EK[14], EK[15]); + encrypt_round(C, D, A, B, EK[16], EK[17]); + encrypt_round(D, A, B, C, EK[18], EK[19]); + + encrypt_round(A, D, C, B, EK[20], EK[21]); + encrypt_round(B, A, D, C, EK[22], EK[23]); + encrypt_round(C, B, A, D, EK[24], EK[25]); + encrypt_round(D, C, B, A, EK[26], EK[27]); + encrypt_round(A, D, C, B, EK[28], EK[29]); + encrypt_round(B, A, D, C, EK[30], EK[31]); + encrypt_round(C, B, A, D, EK[32], EK[33]); + encrypt_round(D, C, B, A, EK[34], EK[35]); + + reverse_mix(A, B, C, D); + + A -= EK[36]; B -= EK[37]; C -= EK[38]; D -= EK[39]; + + store_le(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MARS Decryption +*/ +void MARS::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 3) + EK[39]; + u32bit B = load_le(in, 2) + EK[38]; + u32bit C = load_le(in, 1) + EK[37]; + u32bit D = load_le(in, 0) + EK[36]; + + forward_mix(A, B, C, D); + + decrypt_round(A, B, C, D, EK[35], EK[34]); + decrypt_round(B, C, D, A, EK[33], EK[32]); + decrypt_round(C, D, A, B, EK[31], EK[30]); + decrypt_round(D, A, B, C, EK[29], EK[28]); + decrypt_round(A, B, C, D, EK[27], EK[26]); + decrypt_round(B, C, D, A, EK[25], EK[24]); + decrypt_round(C, D, A, B, EK[23], EK[22]); + decrypt_round(D, A, B, C, EK[21], EK[20]); + + decrypt_round(A, D, C, B, EK[19], EK[18]); + decrypt_round(B, A, D, C, EK[17], EK[16]); + decrypt_round(C, B, A, D, EK[15], EK[14]); + decrypt_round(D, C, B, A, EK[13], EK[12]); + decrypt_round(A, D, C, B, EK[11], EK[10]); + decrypt_round(B, A, D, C, EK[ 9], EK[ 8]); + decrypt_round(C, B, A, D, EK[ 7], EK[ 6]); + decrypt_round(D, C, B, A, EK[ 5], EK[ 4]); + + reverse_mix(A, B, C, D); + + A -= EK[3]; B -= EK[2]; C -= EK[1]; D -= EK[0]; + + store_le(out, D, C, B, A); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MARS Key Schedule +*/ +void MARS::key_schedule(const byte key[], size_t length) + { + secure_vector T(15); + for(size_t i = 0; i != length / 4; ++i) + T[i] = load_le(key, i); + + T[length / 4] = static_cast(length) / 4; + + EK.resize(40); + + for(u32bit i = 0; i != 4; ++i) + { + T[ 0] ^= rotate_left(T[ 8] ^ T[13], 3) ^ (i ); + T[ 1] ^= rotate_left(T[ 9] ^ T[14], 3) ^ (i + 4); + T[ 2] ^= rotate_left(T[10] ^ T[ 0], 3) ^ (i + 8); + T[ 3] ^= rotate_left(T[11] ^ T[ 1], 3) ^ (i + 12); + T[ 4] ^= rotate_left(T[12] ^ T[ 2], 3) ^ (i + 16); + T[ 5] ^= rotate_left(T[13] ^ T[ 3], 3) ^ (i + 20); + T[ 6] ^= rotate_left(T[14] ^ T[ 4], 3) ^ (i + 24); + T[ 7] ^= rotate_left(T[ 0] ^ T[ 5], 3) ^ (i + 28); + T[ 8] ^= rotate_left(T[ 1] ^ T[ 6], 3) ^ (i + 32); + T[ 9] ^= rotate_left(T[ 2] ^ T[ 7], 3) ^ (i + 36); + T[10] ^= rotate_left(T[ 3] ^ T[ 8], 3) ^ (i + 40); + T[11] ^= rotate_left(T[ 4] ^ T[ 9], 3) ^ (i + 44); + T[12] ^= rotate_left(T[ 5] ^ T[10], 3) ^ (i + 48); + T[13] ^= rotate_left(T[ 6] ^ T[11], 3) ^ (i + 52); + T[14] ^= rotate_left(T[ 7] ^ T[12], 3) ^ (i + 56); + + for(size_t j = 0; j != 4; ++j) + { + T[ 0] = rotate_left(T[ 0] + SBOX[T[14] % 512], 9); + T[ 1] = rotate_left(T[ 1] + SBOX[T[ 0] % 512], 9); + T[ 2] = rotate_left(T[ 2] + SBOX[T[ 1] % 512], 9); + T[ 3] = rotate_left(T[ 3] + SBOX[T[ 2] % 512], 9); + T[ 4] = rotate_left(T[ 4] + SBOX[T[ 3] % 512], 9); + T[ 5] = rotate_left(T[ 5] + SBOX[T[ 4] % 512], 9); + T[ 6] = rotate_left(T[ 6] + SBOX[T[ 5] % 512], 9); + T[ 7] = rotate_left(T[ 7] + SBOX[T[ 6] % 512], 9); + T[ 8] = rotate_left(T[ 8] + SBOX[T[ 7] % 512], 9); + T[ 9] = rotate_left(T[ 9] + SBOX[T[ 8] % 512], 9); + T[10] = rotate_left(T[10] + SBOX[T[ 9] % 512], 9); + T[11] = rotate_left(T[11] + SBOX[T[10] % 512], 9); + T[12] = rotate_left(T[12] + SBOX[T[11] % 512], 9); + T[13] = rotate_left(T[13] + SBOX[T[12] % 512], 9); + T[14] = rotate_left(T[14] + SBOX[T[13] % 512], 9); + } + + EK[10*i + 0] = T[ 0]; + EK[10*i + 1] = T[ 4]; + EK[10*i + 2] = T[ 8]; + EK[10*i + 3] = T[12]; + EK[10*i + 4] = T[ 1]; + EK[10*i + 5] = T[ 5]; + EK[10*i + 6] = T[ 9]; + EK[10*i + 7] = T[13]; + EK[10*i + 8] = T[ 2]; + EK[10*i + 9] = T[ 6]; + } + + for(size_t i = 5; i != 37; i += 2) + { + const u32bit key3 = EK[i] & 3; + EK[i] |= 3; + EK[i] ^= rotate_left(SBOX[265 + key3], EK[i-1] % 32) & gen_mask(EK[i]); + } + } + +void MARS::clear() + { + zap(EK); + } + +} diff --git a/src/lib/block/mars/mars.h b/src/lib/block/mars/mars.h new file mode 100644 index 000000000..90f6480e6 --- /dev/null +++ b/src/lib/block/mars/mars.h @@ -0,0 +1,35 @@ +/* +* MARS +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MARS_H__ +#define BOTAN_MARS_H__ + +#include + +namespace Botan { + +/** +* MARS, IBM's candidate for AES +*/ +class BOTAN_DLL MARS : public Block_Cipher_Fixed_Params<16, 16, 32, 4> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "MARS"; } + BlockCipher* clone() const { return new MARS; } + private: + void key_schedule(const byte[], size_t); + + secure_vector EK; + }; + +} + +#endif diff --git a/src/lib/block/misty1/info.txt b/src/lib/block/misty1/info.txt new file mode 100644 index 000000000..568f13574 --- /dev/null +++ b/src/lib/block/misty1/info.txt @@ -0,0 +1 @@ +define MISTY1 20131128 diff --git a/src/lib/block/misty1/misty1.cpp b/src/lib/block/misty1/misty1.cpp new file mode 100644 index 000000000..98f20eee8 --- /dev/null +++ b/src/lib/block/misty1/misty1.cpp @@ -0,0 +1,270 @@ +/* +* MISTY1 +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +static const byte MISTY1_SBOX_S7[128] = { + 0x1B, 0x32, 0x33, 0x5A, 0x3B, 0x10, 0x17, 0x54, 0x5B, 0x1A, 0x72, 0x73, + 0x6B, 0x2C, 0x66, 0x49, 0x1F, 0x24, 0x13, 0x6C, 0x37, 0x2E, 0x3F, 0x4A, + 0x5D, 0x0F, 0x40, 0x56, 0x25, 0x51, 0x1C, 0x04, 0x0B, 0x46, 0x20, 0x0D, + 0x7B, 0x35, 0x44, 0x42, 0x2B, 0x1E, 0x41, 0x14, 0x4B, 0x79, 0x15, 0x6F, + 0x0E, 0x55, 0x09, 0x36, 0x74, 0x0C, 0x67, 0x53, 0x28, 0x0A, 0x7E, 0x38, + 0x02, 0x07, 0x60, 0x29, 0x19, 0x12, 0x65, 0x2F, 0x30, 0x39, 0x08, 0x68, + 0x5F, 0x78, 0x2A, 0x4C, 0x64, 0x45, 0x75, 0x3D, 0x59, 0x48, 0x03, 0x57, + 0x7C, 0x4F, 0x62, 0x3C, 0x1D, 0x21, 0x5E, 0x27, 0x6A, 0x70, 0x4D, 0x3A, + 0x01, 0x6D, 0x6E, 0x63, 0x18, 0x77, 0x23, 0x05, 0x26, 0x76, 0x00, 0x31, + 0x2D, 0x7A, 0x7F, 0x61, 0x50, 0x22, 0x11, 0x06, 0x47, 0x16, 0x52, 0x4E, + 0x71, 0x3E, 0x69, 0x43, 0x34, 0x5C, 0x58, 0x7D }; + +static const u16bit MISTY1_SBOX_S9[512] = { + 0x01C3, 0x00CB, 0x0153, 0x019F, 0x01E3, 0x00E9, 0x00FB, 0x0035, 0x0181, + 0x00B9, 0x0117, 0x01EB, 0x0133, 0x0009, 0x002D, 0x00D3, 0x00C7, 0x014A, + 0x0037, 0x007E, 0x00EB, 0x0164, 0x0193, 0x01D8, 0x00A3, 0x011E, 0x0055, + 0x002C, 0x001D, 0x01A2, 0x0163, 0x0118, 0x014B, 0x0152, 0x01D2, 0x000F, + 0x002B, 0x0030, 0x013A, 0x00E5, 0x0111, 0x0138, 0x018E, 0x0063, 0x00E3, + 0x00C8, 0x01F4, 0x001B, 0x0001, 0x009D, 0x00F8, 0x01A0, 0x016D, 0x01F3, + 0x001C, 0x0146, 0x007D, 0x00D1, 0x0082, 0x01EA, 0x0183, 0x012D, 0x00F4, + 0x019E, 0x01D3, 0x00DD, 0x01E2, 0x0128, 0x01E0, 0x00EC, 0x0059, 0x0091, + 0x0011, 0x012F, 0x0026, 0x00DC, 0x00B0, 0x018C, 0x010F, 0x01F7, 0x00E7, + 0x016C, 0x00B6, 0x00F9, 0x00D8, 0x0151, 0x0101, 0x014C, 0x0103, 0x00B8, + 0x0154, 0x012B, 0x01AE, 0x0017, 0x0071, 0x000C, 0x0047, 0x0058, 0x007F, + 0x01A4, 0x0134, 0x0129, 0x0084, 0x015D, 0x019D, 0x01B2, 0x01A3, 0x0048, + 0x007C, 0x0051, 0x01CA, 0x0023, 0x013D, 0x01A7, 0x0165, 0x003B, 0x0042, + 0x00DA, 0x0192, 0x00CE, 0x00C1, 0x006B, 0x009F, 0x01F1, 0x012C, 0x0184, + 0x00FA, 0x0196, 0x01E1, 0x0169, 0x017D, 0x0031, 0x0180, 0x010A, 0x0094, + 0x01DA, 0x0186, 0x013E, 0x011C, 0x0060, 0x0175, 0x01CF, 0x0067, 0x0119, + 0x0065, 0x0068, 0x0099, 0x0150, 0x0008, 0x0007, 0x017C, 0x00B7, 0x0024, + 0x0019, 0x00DE, 0x0127, 0x00DB, 0x00E4, 0x01A9, 0x0052, 0x0109, 0x0090, + 0x019C, 0x01C1, 0x0028, 0x01B3, 0x0135, 0x016A, 0x0176, 0x00DF, 0x01E5, + 0x0188, 0x00C5, 0x016E, 0x01DE, 0x01B1, 0x00C3, 0x01DF, 0x0036, 0x00EE, + 0x01EE, 0x00F0, 0x0093, 0x0049, 0x009A, 0x01B6, 0x0069, 0x0081, 0x0125, + 0x000B, 0x005E, 0x00B4, 0x0149, 0x01C7, 0x0174, 0x003E, 0x013B, 0x01B7, + 0x008E, 0x01C6, 0x00AE, 0x0010, 0x0095, 0x01EF, 0x004E, 0x00F2, 0x01FD, + 0x0085, 0x00FD, 0x00F6, 0x00A0, 0x016F, 0x0083, 0x008A, 0x0156, 0x009B, + 0x013C, 0x0107, 0x0167, 0x0098, 0x01D0, 0x01E9, 0x0003, 0x01FE, 0x00BD, + 0x0122, 0x0089, 0x00D2, 0x018F, 0x0012, 0x0033, 0x006A, 0x0142, 0x00ED, + 0x0170, 0x011B, 0x00E2, 0x014F, 0x0158, 0x0131, 0x0147, 0x005D, 0x0113, + 0x01CD, 0x0079, 0x0161, 0x01A5, 0x0179, 0x009E, 0x01B4, 0x00CC, 0x0022, + 0x0132, 0x001A, 0x00E8, 0x0004, 0x0187, 0x01ED, 0x0197, 0x0039, 0x01BF, + 0x01D7, 0x0027, 0x018B, 0x00C6, 0x009C, 0x00D0, 0x014E, 0x006C, 0x0034, + 0x01F2, 0x006E, 0x00CA, 0x0025, 0x00BA, 0x0191, 0x00FE, 0x0013, 0x0106, + 0x002F, 0x01AD, 0x0172, 0x01DB, 0x00C0, 0x010B, 0x01D6, 0x00F5, 0x01EC, + 0x010D, 0x0076, 0x0114, 0x01AB, 0x0075, 0x010C, 0x01E4, 0x0159, 0x0054, + 0x011F, 0x004B, 0x00C4, 0x01BE, 0x00F7, 0x0029, 0x00A4, 0x000E, 0x01F0, + 0x0077, 0x004D, 0x017A, 0x0086, 0x008B, 0x00B3, 0x0171, 0x00BF, 0x010E, + 0x0104, 0x0097, 0x015B, 0x0160, 0x0168, 0x00D7, 0x00BB, 0x0066, 0x01CE, + 0x00FC, 0x0092, 0x01C5, 0x006F, 0x0016, 0x004A, 0x00A1, 0x0139, 0x00AF, + 0x00F1, 0x0190, 0x000A, 0x01AA, 0x0143, 0x017B, 0x0056, 0x018D, 0x0166, + 0x00D4, 0x01FB, 0x014D, 0x0194, 0x019A, 0x0087, 0x01F8, 0x0123, 0x00A7, + 0x01B8, 0x0141, 0x003C, 0x01F9, 0x0140, 0x002A, 0x0155, 0x011A, 0x01A1, + 0x0198, 0x00D5, 0x0126, 0x01AF, 0x0061, 0x012E, 0x0157, 0x01DC, 0x0072, + 0x018A, 0x00AA, 0x0096, 0x0115, 0x00EF, 0x0045, 0x007B, 0x008D, 0x0145, + 0x0053, 0x005F, 0x0178, 0x00B2, 0x002E, 0x0020, 0x01D5, 0x003F, 0x01C9, + 0x01E7, 0x01AC, 0x0044, 0x0038, 0x0014, 0x00B1, 0x016B, 0x00AB, 0x00B5, + 0x005A, 0x0182, 0x01C8, 0x01D4, 0x0018, 0x0177, 0x0064, 0x00CF, 0x006D, + 0x0100, 0x0199, 0x0130, 0x015A, 0x0005, 0x0120, 0x01BB, 0x01BD, 0x00E0, + 0x004F, 0x00D6, 0x013F, 0x01C4, 0x012A, 0x0015, 0x0006, 0x00FF, 0x019B, + 0x00A6, 0x0043, 0x0088, 0x0050, 0x015F, 0x01E8, 0x0121, 0x0073, 0x017E, + 0x00BC, 0x00C2, 0x00C9, 0x0173, 0x0189, 0x01F5, 0x0074, 0x01CC, 0x01E6, + 0x01A8, 0x0195, 0x001F, 0x0041, 0x000D, 0x01BA, 0x0032, 0x003D, 0x01D1, + 0x0080, 0x00A8, 0x0057, 0x01B9, 0x0162, 0x0148, 0x00D9, 0x0105, 0x0062, + 0x007A, 0x0021, 0x01FF, 0x0112, 0x0108, 0x01C0, 0x00A9, 0x011D, 0x01B0, + 0x01A6, 0x00CD, 0x00F3, 0x005C, 0x0102, 0x005B, 0x01D9, 0x0144, 0x01F6, + 0x00AD, 0x00A5, 0x003A, 0x01CB, 0x0136, 0x017F, 0x0046, 0x00E1, 0x001E, + 0x01DD, 0x00E6, 0x0137, 0x01FA, 0x0185, 0x008C, 0x008F, 0x0040, 0x01B5, + 0x00BE, 0x0078, 0x0000, 0x00AC, 0x0110, 0x015E, 0x0124, 0x0002, 0x01BC, + 0x00A2, 0x00EA, 0x0070, 0x01FC, 0x0116, 0x015C, 0x004C, 0x01C2 }; + +/* +* MISTY1 FI Function +*/ +u16bit FI(u16bit input, u16bit key7, u16bit key9) + { + u16bit D9 = input >> 7, D7 = input & 0x7F; + D9 = MISTY1_SBOX_S9[D9] ^ D7; + D7 = (MISTY1_SBOX_S7[D7] ^ key7 ^ D9) & 0x7F; + D9 = MISTY1_SBOX_S9[D9 ^ key9] ^ D7; + return static_cast((D7 << 9) | D9); + } + +} + +/* +* MISTY1 Encryption +*/ +void MISTY1::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 0); + u16bit B1 = load_be(in, 1); + u16bit B2 = load_be(in, 2); + u16bit B3 = load_be(in, 3); + + for(size_t j = 0; j != 12; j += 3) + { + const u16bit* RK = &EK[8 * j]; + + B1 ^= B0 & RK[0]; + B0 ^= B1 | RK[1]; + B3 ^= B2 & RK[2]; + B2 ^= B3 | RK[3]; + + u32bit T0, T1; + + T0 = FI(B0 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B1; + T1 = FI(B1 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; + T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; + + B2 ^= T1 ^ RK[13]; + B3 ^= T0; + + T0 = FI(B2 ^ RK[14], RK[15], RK[16]) ^ B3; + T1 = FI(B3 ^ RK[17], RK[18], RK[19]) ^ T0; + T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; + + B0 ^= T1 ^ RK[23]; + B1 ^= T0; + } + + B1 ^= B0 & EK[96]; + B0 ^= B1 | EK[97]; + B3 ^= B2 & EK[98]; + B2 ^= B3 | EK[99]; + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MISTY1 Decryption +*/ +void MISTY1::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 2); + u16bit B1 = load_be(in, 3); + u16bit B2 = load_be(in, 0); + u16bit B3 = load_be(in, 1); + + for(size_t j = 0; j != 12; j += 3) + { + const u16bit* RK = &DK[8 * j]; + + B2 ^= B3 | RK[0]; + B3 ^= B2 & RK[1]; + B0 ^= B1 | RK[2]; + B1 ^= B0 & RK[3]; + + u32bit T0, T1; + + T0 = FI(B2 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B3; + T1 = FI(B3 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; + T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; + + B0 ^= T1 ^ RK[13]; + B1 ^= T0; + + T0 = FI(B0 ^ RK[14], RK[15], RK[16]) ^ B1; + T1 = FI(B1 ^ RK[17], RK[18], RK[19]) ^ T0; + T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; + + B2 ^= T1 ^ RK[23]; + B3 ^= T0; + } + + B2 ^= B3 | DK[96]; + B3 ^= B2 & DK[97]; + B0 ^= B1 | DK[98]; + B1 ^= B0 & DK[99]; + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MISTY1 Key Schedule +*/ +void MISTY1::key_schedule(const byte key[], size_t length) + { + secure_vector KS(32); + for(size_t i = 0; i != length / 2; ++i) + KS[i] = load_be(key, i); + + for(size_t i = 0; i != 8; ++i) + { + KS[i+ 8] = FI(KS[i], KS[(i+1) % 8] >> 9, KS[(i+1) % 8] & 0x1FF); + KS[i+16] = KS[i+8] >> 9; + KS[i+24] = KS[i+8] & 0x1FF; + } + + /* + * Precomputed indexes for the orderings of the subkeys (MISTY1 reuses + * values) + */ + static const byte EK_ORDER[100] = { + 0x00, 0x0E, 0x0A, 0x04, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, + 0x1B, 0x04, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, 0x1C, 0x05, + 0x01, 0x0F, 0x0B, 0x05, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, + 0x1D, 0x06, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, 0x1E, 0x07, + 0x02, 0x08, 0x0C, 0x06, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, + 0x1F, 0x00, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, 0x18, 0x01, + 0x03, 0x09, 0x0D, 0x07, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, + 0x19, 0x02, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, 0x1A, 0x03, + 0x04, 0x0A, 0x0E, 0x00 }; + + static const byte DK_ORDER[100] = { + 0x00, 0x0E, 0x0A, 0x04, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, + 0x1A, 0x03, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, 0x19, 0x02, + 0x07, 0x0D, 0x09, 0x03, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, + 0x18, 0x01, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, 0x1F, 0x00, + 0x06, 0x0C, 0x08, 0x02, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, + 0x1E, 0x07, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, 0x1D, 0x06, + 0x05, 0x0B, 0x0F, 0x01, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, + 0x1C, 0x05, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, 0x1B, 0x04, + 0x04, 0x0A, 0x0E, 0x00 }; + + EK.resize(100); + DK.resize(100); + + for(size_t i = 0; i != 100; ++i) + { + EK[i] = KS[EK_ORDER[i]]; + DK[i] = KS[DK_ORDER[i]]; + } + } + +void MISTY1::clear() + { + zap(EK); + zap(DK); + } + +/* +* MISTY1 Constructor +*/ +MISTY1::MISTY1(size_t rounds) + { + if(rounds != 8) + throw Invalid_Argument("MISTY1: Invalid number of rounds: " + + std::to_string(rounds)); + } + +} diff --git a/src/lib/block/misty1/misty1.h b/src/lib/block/misty1/misty1.h new file mode 100644 index 000000000..40917b08b --- /dev/null +++ b/src/lib/block/misty1/misty1.h @@ -0,0 +1,41 @@ +/* +* MISTY1 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MISTY1_H__ +#define BOTAN_MISTY1_H__ + +#include + +namespace Botan { + +/** +* MISTY1 +*/ +class BOTAN_DLL MISTY1 : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "MISTY1"; } + BlockCipher* clone() const { return new MISTY1; } + + /** + * @param rounds the number of rounds. Must be 8 with the current + * implementation + */ + MISTY1(size_t rounds = 8); + private: + void key_schedule(const byte[], size_t); + + secure_vector EK, DK; + }; + +} + +#endif diff --git a/src/lib/block/noekeon/info.txt b/src/lib/block/noekeon/info.txt new file mode 100644 index 000000000..769d7150e --- /dev/null +++ b/src/lib/block/noekeon/info.txt @@ -0,0 +1 @@ +define NOEKEON 20131128 diff --git a/src/lib/block/noekeon/noekeon.cpp b/src/lib/block/noekeon/noekeon.cpp new file mode 100644 index 000000000..53e67e5e6 --- /dev/null +++ b/src/lib/block/noekeon/noekeon.cpp @@ -0,0 +1,212 @@ +/* +* Noekeon +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Noekeon's Theta Operation +*/ +inline void theta(u32bit& A0, u32bit& A1, + u32bit& A2, u32bit& A3, + const u32bit EK[4]) + { + u32bit T = A0 ^ A2; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A1 ^= T; + A3 ^= T; + + A0 ^= EK[0]; + A1 ^= EK[1]; + A2 ^= EK[2]; + A3 ^= EK[3]; + + T = A1 ^ A3; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A0 ^= T; + A2 ^= T; + } + +/* +* Theta With Null Key +*/ +inline void theta(u32bit& A0, u32bit& A1, + u32bit& A2, u32bit& A3) + { + u32bit T = A0 ^ A2; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A1 ^= T; + A3 ^= T; + + T = A1 ^ A3; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A0 ^= T; + A2 ^= T; + } + +/* +* Noekeon's Gamma S-Box Layer +*/ +inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3) + { + A1 ^= ~A3 & ~A2; + A0 ^= A2 & A1; + + u32bit T = A3; + A3 = A0; + A0 = T; + + A2 ^= A0 ^ A1 ^ A3; + + A1 ^= ~A3 & ~A2; + A0 ^= A2 & A1; + } + +} + +/* +* Noekeon Round Constants +*/ +const byte Noekeon::RC[] = { + 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, + 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, + 0xD4 }; + +/* +* Noekeon Encryption +*/ +void Noekeon::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A0 = load_be(in, 0); + u32bit A1 = load_be(in, 1); + u32bit A2 = load_be(in, 2); + u32bit A3 = load_be(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + A0 ^= RC[j]; + theta(A0, A1, A2, A3, &EK[0]); + + A1 = rotate_left(A1, 1); + A2 = rotate_left(A2, 5); + A3 = rotate_left(A3, 2); + + gamma(A0, A1, A2, A3); + + A1 = rotate_right(A1, 1); + A2 = rotate_right(A2, 5); + A3 = rotate_right(A3, 2); + } + + A0 ^= RC[16]; + theta(A0, A1, A2, A3, &EK[0]); + + store_be(out, A0, A1, A2, A3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Noekeon Encryption +*/ +void Noekeon::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A0 = load_be(in, 0); + u32bit A1 = load_be(in, 1); + u32bit A2 = load_be(in, 2); + u32bit A3 = load_be(in, 3); + + for(size_t j = 16; j != 0; --j) + { + theta(A0, A1, A2, A3, &DK[0]); + A0 ^= RC[j]; + + A1 = rotate_left(A1, 1); + A2 = rotate_left(A2, 5); + A3 = rotate_left(A3, 2); + + gamma(A0, A1, A2, A3); + + A1 = rotate_right(A1, 1); + A2 = rotate_right(A2, 5); + A3 = rotate_right(A3, 2); + } + + theta(A0, A1, A2, A3, &DK[0]); + A0 ^= RC[0]; + + store_be(out, A0, A1, A2, A3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Noekeon Key Schedule +*/ +void Noekeon::key_schedule(const byte key[], size_t) + { + u32bit A0 = load_be(key, 0); + u32bit A1 = load_be(key, 1); + u32bit A2 = load_be(key, 2); + u32bit A3 = load_be(key, 3); + + for(size_t i = 0; i != 16; ++i) + { + A0 ^= RC[i]; + theta(A0, A1, A2, A3); + + A1 = rotate_left(A1, 1); + A2 = rotate_left(A2, 5); + A3 = rotate_left(A3, 2); + + gamma(A0, A1, A2, A3); + + A1 = rotate_right(A1, 1); + A2 = rotate_right(A2, 5); + A3 = rotate_right(A3, 2); + } + + A0 ^= RC[16]; + + DK.resize(4); + DK[0] = A0; + DK[1] = A1; + DK[2] = A2; + DK[3] = A3; + + theta(A0, A1, A2, A3); + + EK.resize(4); + EK[0] = A0; + EK[1] = A1; + EK[2] = A2; + EK[3] = A3; + } + +/* +* Clear memory of sensitive data +*/ +void Noekeon::clear() + { + zap(EK); + zap(DK); + } + +} diff --git a/src/lib/block/noekeon/noekeon.h b/src/lib/block/noekeon/noekeon.h new file mode 100644 index 000000000..108b34cd6 --- /dev/null +++ b/src/lib/block/noekeon/noekeon.h @@ -0,0 +1,50 @@ +/* +* Noekeon +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NOEKEON_H__ +#define BOTAN_NOEKEON_H__ + +#include + +namespace Botan { + +/** +* Noekeon +*/ +class BOTAN_DLL Noekeon : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Noekeon"; } + BlockCipher* clone() const { return new Noekeon; } + protected: + /** + * The Noekeon round constants + */ + static const byte RC[17]; + + /** + * @return const reference to encryption subkeys + */ + const secure_vector& get_EK() const { return EK; } + + /** + * @return const reference to decryption subkeys + */ + const secure_vector& get_DK() const { return DK; } + + private: + void key_schedule(const byte[], size_t); + secure_vector EK, DK; + }; + +} + +#endif diff --git a/src/lib/block/noekeon_simd/info.txt b/src/lib/block/noekeon_simd/info.txt new file mode 100644 index 000000000..78b9d5f12 --- /dev/null +++ b/src/lib/block/noekeon_simd/info.txt @@ -0,0 +1,7 @@ +define NOEKEON_SIMD 20131128 + + +noekeon +simd +simd_engine + diff --git a/src/lib/block/noekeon_simd/noekeon_simd.cpp b/src/lib/block/noekeon_simd/noekeon_simd.cpp new file mode 100644 index 000000000..2a4c1fd74 --- /dev/null +++ b/src/lib/block/noekeon_simd/noekeon_simd.cpp @@ -0,0 +1,177 @@ +/* +* Noekeon in SIMD +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Noekeon's Theta Operation +*/ +#define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3) \ + do { \ + SIMD_32 T = A0 ^ A2; \ + SIMD_32 T_l8 = T; \ + SIMD_32 T_r8 = T; \ + T_l8.rotate_left(8); \ + T_r8.rotate_right(8); \ + T ^= T_l8; \ + T ^= T_r8; \ + A1 ^= T; \ + A3 ^= T; \ + \ + A0 ^= K0; \ + A1 ^= K1; \ + A2 ^= K2; \ + A3 ^= K3; \ + \ + T = A1 ^ A3; \ + T_l8 = T; \ + T_r8 = T; \ + T_l8.rotate_left(8); \ + T_r8.rotate_right(8); \ + T ^= T_l8; \ + T ^= T_r8; \ + A0 ^= T; \ + A2 ^= T; \ + } while(0) + +/* +* Noekeon's Gamma S-Box Layer +*/ +#define NOK_SIMD_GAMMA(A0, A1, A2, A3) \ + do \ + { \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + \ + SIMD_32 T = A3; \ + A3 = A0; \ + A0 = T; \ + \ + A2 ^= A0 ^ A1 ^ A3; \ + \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + } while(0) + +/* +* Noekeon Encryption +*/ +void Noekeon_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const secure_vector& EK = this->get_EK(); + + SIMD_32 K0 = SIMD_32(EK[0]); + SIMD_32 K1 = SIMD_32(EK[1]); + SIMD_32 K2 = SIMD_32(EK[2]); + SIMD_32 K3 = SIMD_32(EK[3]); + + while(blocks >= 4) + { + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(A0, A1, A2, A3); + + for(size_t i = 0; i != 16; ++i) + { + A0 ^= SIMD_32(RC[i]); + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } + + A0 ^= SIMD_32(RC[16]); + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + + in += 64; + out += 64; + blocks -= 4; + } + + if(blocks) + Noekeon::encrypt_n(in, out, blocks); + } + +/* +* Noekeon Encryption +*/ +void Noekeon_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const secure_vector& DK = this->get_DK(); + + SIMD_32 K0 = SIMD_32(DK[0]); + SIMD_32 K1 = SIMD_32(DK[1]); + SIMD_32 K2 = SIMD_32(DK[2]); + SIMD_32 K3 = SIMD_32(DK[3]); + + while(blocks >= 4) + { + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(A0, A1, A2, A3); + + for(size_t i = 0; i != 16; ++i) + { + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A0 ^= SIMD_32(RC[16-i]); + + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + A0 ^= SIMD_32(RC[0]); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + + in += 64; + out += 64; + blocks -= 4; + } + + if(blocks) + Noekeon::decrypt_n(in, out, blocks); + } + +} diff --git a/src/lib/block/noekeon_simd/noekeon_simd.h b/src/lib/block/noekeon_simd/noekeon_simd.h new file mode 100644 index 000000000..5cc2d8b09 --- /dev/null +++ b/src/lib/block/noekeon_simd/noekeon_simd.h @@ -0,0 +1,31 @@ +/* +* Noekeon in SIMD +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NOEKEON_SIMD_H__ +#define BOTAN_NOEKEON_SIMD_H__ + +#include + +namespace Botan { + +/** +* Noekeon implementation using SIMD operations +*/ +class BOTAN_DLL Noekeon_SIMD : public Noekeon + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + BlockCipher* clone() const { return new Noekeon_SIMD; } + }; + +} + +#endif diff --git a/src/lib/block/rc2/info.txt b/src/lib/block/rc2/info.txt new file mode 100644 index 000000000..fae09cf23 --- /dev/null +++ b/src/lib/block/rc2/info.txt @@ -0,0 +1 @@ +define RC2 20131128 diff --git a/src/lib/block/rc2/rc2.cpp b/src/lib/block/rc2/rc2.cpp new file mode 100644 index 000000000..d7c76a7a6 --- /dev/null +++ b/src/lib/block/rc2/rc2.cpp @@ -0,0 +1,182 @@ +/* +* RC2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* RC2 Encryption +*/ +void RC2::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit R0 = load_le(in, 0); + u16bit R1 = load_le(in, 1); + u16bit R2 = load_le(in, 2); + u16bit R3 = load_le(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + R0 += (R1 & ~R3) + (R2 & R3) + K[4*j]; + R0 = rotate_left(R0, 1); + + R1 += (R2 & ~R0) + (R3 & R0) + K[4*j + 1]; + R1 = rotate_left(R1, 2); + + R2 += (R3 & ~R1) + (R0 & R1) + K[4*j + 2]; + R2 = rotate_left(R2, 3); + + R3 += (R0 & ~R2) + (R1 & R2) + K[4*j + 3]; + R3 = rotate_left(R3, 5); + + if(j == 4 || j == 10) + { + R0 += K[R3 % 64]; + R1 += K[R0 % 64]; + R2 += K[R1 % 64]; + R3 += K[R2 % 64]; + } + } + + store_le(out, R0, R1, R2, R3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC2 Decryption +*/ +void RC2::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit R0 = load_le(in, 0); + u16bit R1 = load_le(in, 1); + u16bit R2 = load_le(in, 2); + u16bit R3 = load_le(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + R3 = rotate_right(R3, 5); + R3 -= (R0 & ~R2) + (R1 & R2) + K[63 - (4*j + 0)]; + + R2 = rotate_right(R2, 3); + R2 -= (R3 & ~R1) + (R0 & R1) + K[63 - (4*j + 1)]; + + R1 = rotate_right(R1, 2); + R1 -= (R2 & ~R0) + (R3 & R0) + K[63 - (4*j + 2)]; + + R0 = rotate_right(R0, 1); + R0 -= (R1 & ~R3) + (R2 & R3) + K[63 - (4*j + 3)]; + + if(j == 4 || j == 10) + { + R3 -= K[R2 % 64]; + R2 -= K[R1 % 64]; + R1 -= K[R0 % 64]; + R0 -= K[R3 % 64]; + } + } + + store_le(out, R0, R1, R2, R3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC2 Key Schedule +*/ +void RC2::key_schedule(const byte key[], size_t length) + { + static const byte TABLE[256] = { + 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 0x28, 0xE9, 0xFD, 0x79, + 0x4A, 0xA0, 0xD8, 0x9D, 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, + 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 0x17, 0x9A, 0x59, 0xF5, + 0x87, 0xB3, 0x4F, 0x13, 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, + 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 0xF0, 0x95, 0x21, 0x22, + 0x5C, 0x6B, 0x4E, 0x82, 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, + 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 0x12, 0x75, 0xCA, 0x1F, + 0x3B, 0xBE, 0xE4, 0xD1, 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, + 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 0x27, 0xF2, 0x1D, 0x9B, + 0xBC, 0x94, 0x43, 0x03, 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, + 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 0x08, 0xE8, 0xEA, 0xDE, + 0x80, 0x52, 0xEE, 0xF7, 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, + 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 0x4B, 0x9F, 0xD0, 0x5E, + 0x04, 0x18, 0xA4, 0xEC, 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, + 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 0x99, 0x7C, 0x3A, 0x85, + 0x23, 0xB8, 0xB4, 0x7A, 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, + 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 0x05, 0xDF, 0x29, 0x10, + 0x67, 0x6C, 0xBA, 0xC9, 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, + 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 0x0D, 0x38, 0x34, 0x1B, + 0xAB, 0x33, 0xFF, 0xB0, 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, + 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 0x0A, 0xA6, 0x20, 0x68, + 0xFE, 0x7F, 0xC1, 0xAD }; + + secure_vector L(128); + copy_mem(&L[0], key, length); + + for(size_t i = length; i != 128; ++i) + L[i] = TABLE[(L[i-1] + L[i-length]) % 256]; + + L[128-length] = TABLE[L[128-length]]; + + for(s32bit i = 127-length; i >= 0; --i) + L[i] = TABLE[L[i+1] ^ L[i+length]]; + + K.resize(64); + load_le(&K[0], &L[0], 64); + } + +void RC2::clear() + { + zap(K); + } + +/* +* Return the code of the effective key bits +*/ +byte RC2::EKB_code(size_t ekb) + { + const byte EKB[256] = { + 0xBD, 0x56, 0xEA, 0xF2, 0xA2, 0xF1, 0xAC, 0x2A, 0xB0, 0x93, 0xD1, 0x9C, + 0x1B, 0x33, 0xFD, 0xD0, 0x30, 0x04, 0xB6, 0xDC, 0x7D, 0xDF, 0x32, 0x4B, + 0xF7, 0xCB, 0x45, 0x9B, 0x31, 0xBB, 0x21, 0x5A, 0x41, 0x9F, 0xE1, 0xD9, + 0x4A, 0x4D, 0x9E, 0xDA, 0xA0, 0x68, 0x2C, 0xC3, 0x27, 0x5F, 0x80, 0x36, + 0x3E, 0xEE, 0xFB, 0x95, 0x1A, 0xFE, 0xCE, 0xA8, 0x34, 0xA9, 0x13, 0xF0, + 0xA6, 0x3F, 0xD8, 0x0C, 0x78, 0x24, 0xAF, 0x23, 0x52, 0xC1, 0x67, 0x17, + 0xF5, 0x66, 0x90, 0xE7, 0xE8, 0x07, 0xB8, 0x60, 0x48, 0xE6, 0x1E, 0x53, + 0xF3, 0x92, 0xA4, 0x72, 0x8C, 0x08, 0x15, 0x6E, 0x86, 0x00, 0x84, 0xFA, + 0xF4, 0x7F, 0x8A, 0x42, 0x19, 0xF6, 0xDB, 0xCD, 0x14, 0x8D, 0x50, 0x12, + 0xBA, 0x3C, 0x06, 0x4E, 0xEC, 0xB3, 0x35, 0x11, 0xA1, 0x88, 0x8E, 0x2B, + 0x94, 0x99, 0xB7, 0x71, 0x74, 0xD3, 0xE4, 0xBF, 0x3A, 0xDE, 0x96, 0x0E, + 0xBC, 0x0A, 0xED, 0x77, 0xFC, 0x37, 0x6B, 0x03, 0x79, 0x89, 0x62, 0xC6, + 0xD7, 0xC0, 0xD2, 0x7C, 0x6A, 0x8B, 0x22, 0xA3, 0x5B, 0x05, 0x5D, 0x02, + 0x75, 0xD5, 0x61, 0xE3, 0x18, 0x8F, 0x55, 0x51, 0xAD, 0x1F, 0x0B, 0x5E, + 0x85, 0xE5, 0xC2, 0x57, 0x63, 0xCA, 0x3D, 0x6C, 0xB4, 0xC5, 0xCC, 0x70, + 0xB2, 0x91, 0x59, 0x0D, 0x47, 0x20, 0xC8, 0x4F, 0x58, 0xE0, 0x01, 0xE2, + 0x16, 0x38, 0xC4, 0x6F, 0x3B, 0x0F, 0x65, 0x46, 0xBE, 0x7E, 0x2D, 0x7B, + 0x82, 0xF9, 0x40, 0xB5, 0x1D, 0x73, 0xF8, 0xEB, 0x26, 0xC7, 0x87, 0x97, + 0x25, 0x54, 0xB1, 0x28, 0xAA, 0x98, 0x9D, 0xA5, 0x64, 0x6D, 0x7A, 0xD4, + 0x10, 0x81, 0x44, 0xEF, 0x49, 0xD6, 0xAE, 0x2E, 0xDD, 0x76, 0x5C, 0x2F, + 0xA7, 0x1C, 0xC9, 0x09, 0x69, 0x9A, 0x83, 0xCF, 0x29, 0x39, 0xB9, 0xE9, + 0x4C, 0xFF, 0x43, 0xAB }; + + if(ekb < 256) + return EKB[ekb]; + else + throw Encoding_Error("RC2::EKB_code: EKB is too large"); + } + +} diff --git a/src/lib/block/rc2/rc2.h b/src/lib/block/rc2/rc2.h new file mode 100644 index 000000000..ae41c9ce2 --- /dev/null +++ b/src/lib/block/rc2/rc2.h @@ -0,0 +1,42 @@ +/* +* RC2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RC2_H__ +#define BOTAN_RC2_H__ + +#include + +namespace Botan { + +/** +* RC2 +*/ +class BOTAN_DLL RC2 : public Block_Cipher_Fixed_Params<8, 1, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + /** + * Return the code of the effective key bits + * @param bits key length + * @return EKB code + */ + static byte EKB_code(size_t bits); + + void clear(); + std::string name() const { return "RC2"; } + BlockCipher* clone() const { return new RC2; } + private: + void key_schedule(const byte[], size_t); + + secure_vector K; + }; + +} + +#endif diff --git a/src/lib/block/rc5/info.txt b/src/lib/block/rc5/info.txt new file mode 100644 index 000000000..2c2c613ba --- /dev/null +++ b/src/lib/block/rc5/info.txt @@ -0,0 +1 @@ +define RC5 20131128 diff --git a/src/lib/block/rc5/rc5.cpp b/src/lib/block/rc5/rc5.cpp new file mode 100644 index 000000000..f370e6cfb --- /dev/null +++ b/src/lib/block/rc5/rc5.cpp @@ -0,0 +1,135 @@ +/* +* RC5 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* RC5 Encryption +*/ +void RC5::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + + A += S[0]; B += S[1]; + for(size_t j = 0; j != rounds; j += 4) + { + A = rotate_left(A ^ B, B % 32) + S[2*j+2]; + B = rotate_left(B ^ A, A % 32) + S[2*j+3]; + + A = rotate_left(A ^ B, B % 32) + S[2*j+4]; + B = rotate_left(B ^ A, A % 32) + S[2*j+5]; + + A = rotate_left(A ^ B, B % 32) + S[2*j+6]; + B = rotate_left(B ^ A, A % 32) + S[2*j+7]; + + A = rotate_left(A ^ B, B % 32) + S[2*j+8]; + B = rotate_left(B ^ A, A % 32) + S[2*j+9]; + } + + store_le(out, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC5 Decryption +*/ +void RC5::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + + for(size_t j = rounds; j != 0; j -= 4) + { + B = rotate_right(B - S[2*j+1], A % 32) ^ A; + A = rotate_right(A - S[2*j ], B % 32) ^ B; + + B = rotate_right(B - S[2*j-1], A % 32) ^ A; + A = rotate_right(A - S[2*j-2], B % 32) ^ B; + + B = rotate_right(B - S[2*j-3], A % 32) ^ A; + A = rotate_right(A - S[2*j-4], B % 32) ^ B; + + B = rotate_right(B - S[2*j-5], A % 32) ^ A; + A = rotate_right(A - S[2*j-6], B % 32) ^ B; + } + B -= S[1]; A -= S[0]; + + store_le(out, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC5 Key Schedule +*/ +void RC5::key_schedule(const byte key[], size_t length) + { + S.resize(2*rounds + 2); + + const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1); + const size_t MIX_ROUNDS = 3 * std::max(WORD_KEYLENGTH, S.size()); + + S[0] = 0xB7E15163; + for(size_t i = 1; i != S.size(); ++i) + S[i] = S[i-1] + 0x9E3779B9; + + secure_vector K(8); + + for(s32bit i = length-1; i >= 0; --i) + K[i/4] = (K[i/4] << 8) + key[i]; + + u32bit A = 0, B = 0; + + for(size_t i = 0; i != MIX_ROUNDS; ++i) + { + A = rotate_left(S[i % S.size()] + A + B, 3); + B = rotate_left(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32); + S[i % S.size()] = A; + K[i % WORD_KEYLENGTH] = B; + } + } + +void RC5::clear() + { + zap(S); + } + +/* +* Return the name of this type +*/ +std::string RC5::name() const + { + return "RC5(" + std::to_string(rounds) + ")"; + } + +/* +* RC5 Constructor +*/ +RC5::RC5(size_t r) : rounds(r) + { + if(rounds < 8 || rounds > 32 || (rounds % 4 != 0)) + throw Invalid_Argument("RC5: Invalid number of rounds " + + std::to_string(rounds)); + } + +} diff --git a/src/lib/block/rc5/rc5.h b/src/lib/block/rc5/rc5.h new file mode 100644 index 000000000..9055974e5 --- /dev/null +++ b/src/lib/block/rc5/rc5.h @@ -0,0 +1,42 @@ +/* +* RC5 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RC5_H__ +#define BOTAN_RC5_H__ + +#include + +namespace Botan { + +/** +* RC5 +*/ +class BOTAN_DLL RC5 : public Block_Cipher_Fixed_Params<8, 1, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const; + BlockCipher* clone() const { return new RC5(rounds); } + + /** + * @param rounds the number of RC5 rounds to run. Must be between + * 8 and 32 and a multiple of 4. + */ + RC5(size_t rounds); + private: + void key_schedule(const byte[], size_t); + + size_t rounds; + secure_vector S; + }; + +} + +#endif diff --git a/src/lib/block/rc6/info.txt b/src/lib/block/rc6/info.txt new file mode 100644 index 000000000..e54379f65 --- /dev/null +++ b/src/lib/block/rc6/info.txt @@ -0,0 +1 @@ +define RC6 20131128 diff --git a/src/lib/block/rc6/rc6.cpp b/src/lib/block/rc6/rc6.cpp new file mode 100644 index 000000000..01255954d --- /dev/null +++ b/src/lib/block/rc6/rc6.cpp @@ -0,0 +1,145 @@ +/* +* RC6 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* RC6 Encryption +*/ +void RC6::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + u32bit C = load_le(in, 2); + u32bit D = load_le(in, 3); + + B += S[0]; D += S[1]; + + for(size_t j = 0; j != 20; j += 4) + { + u32bit T1, T2; + + T1 = rotate_left(B*(2*B+1), 5); + T2 = rotate_left(D*(2*D+1), 5); + A = rotate_left(A ^ T1, T2 % 32) + S[2*j+2]; + C = rotate_left(C ^ T2, T1 % 32) + S[2*j+3]; + + T1 = rotate_left(C*(2*C+1), 5); + T2 = rotate_left(A*(2*A+1), 5); + B = rotate_left(B ^ T1, T2 % 32) + S[2*j+4]; + D = rotate_left(D ^ T2, T1 % 32) + S[2*j+5]; + + T1 = rotate_left(D*(2*D+1), 5); + T2 = rotate_left(B*(2*B+1), 5); + C = rotate_left(C ^ T1, T2 % 32) + S[2*j+6]; + A = rotate_left(A ^ T2, T1 % 32) + S[2*j+7]; + + T1 = rotate_left(A*(2*A+1), 5); + T2 = rotate_left(C*(2*C+1), 5); + D = rotate_left(D ^ T1, T2 % 32) + S[2*j+8]; + B = rotate_left(B ^ T2, T1 % 32) + S[2*j+9]; + } + + A += S[42]; C += S[43]; + + store_le(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC6 Decryption +*/ +void RC6::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + u32bit C = load_le(in, 2); + u32bit D = load_le(in, 3); + + C -= S[43]; A -= S[42]; + + for(size_t j = 0; j != 20; j += 4) + { + u32bit T1, T2; + + T1 = rotate_left(A*(2*A+1), 5); + T2 = rotate_left(C*(2*C+1), 5); + B = rotate_right(B - S[41 - 2*j], T1 % 32) ^ T2; + D = rotate_right(D - S[40 - 2*j], T2 % 32) ^ T1; + + T1 = rotate_left(D*(2*D+1), 5); + T2 = rotate_left(B*(2*B+1), 5); + A = rotate_right(A - S[39 - 2*j], T1 % 32) ^ T2; + C = rotate_right(C - S[38 - 2*j], T2 % 32) ^ T1; + + T1 = rotate_left(C*(2*C+1), 5); + T2 = rotate_left(A*(2*A+1), 5); + D = rotate_right(D - S[37 - 2*j], T1 % 32) ^ T2; + B = rotate_right(B - S[36 - 2*j], T2 % 32) ^ T1; + + T1 = rotate_left(B*(2*B+1), 5); + T2 = rotate_left(D*(2*D+1), 5); + C = rotate_right(C - S[35 - 2*j], T1 % 32) ^ T2; + A = rotate_right(A - S[34 - 2*j], T2 % 32) ^ T1; + } + + D -= S[1]; B -= S[0]; + + store_le(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC6 Key Schedule +*/ +void RC6::key_schedule(const byte key[], size_t length) + { + S.resize(44); + + const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1); + const size_t MIX_ROUNDS = 3 * std::max(WORD_KEYLENGTH, S.size()); + + S[0] = 0xB7E15163; + for(size_t i = 1; i != S.size(); ++i) + S[i] = S[i-1] + 0x9E3779B9; + + secure_vector K(8); + + for(s32bit i = length-1; i >= 0; --i) + K[i/4] = (K[i/4] << 8) + key[i]; + + u32bit A = 0, B = 0; + for(size_t i = 0; i != MIX_ROUNDS; ++i) + { + A = rotate_left(S[i % S.size()] + A + B, 3); + B = rotate_left(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32); + S[i % S.size()] = A; + K[i % WORD_KEYLENGTH] = B; + } + } + +void RC6::clear() + { + zap(S); + } + +} diff --git a/src/lib/block/rc6/rc6.h b/src/lib/block/rc6/rc6.h new file mode 100644 index 000000000..4331c3e0f --- /dev/null +++ b/src/lib/block/rc6/rc6.h @@ -0,0 +1,35 @@ +/* +* RC6 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RC6_H__ +#define BOTAN_RC6_H__ + +#include + +namespace Botan { + +/** +* RC6, Ron Rivest's AES candidate +*/ +class BOTAN_DLL RC6 : public Block_Cipher_Fixed_Params<16, 1, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "RC6"; } + BlockCipher* clone() const { return new RC6; } + private: + void key_schedule(const byte[], size_t); + + secure_vector S; + }; + +} + +#endif diff --git a/src/lib/block/safer/info.txt b/src/lib/block/safer/info.txt new file mode 100644 index 000000000..ad7841dab --- /dev/null +++ b/src/lib/block/safer/info.txt @@ -0,0 +1 @@ +define SAFER 20131128 diff --git a/src/lib/block/safer/safer_sk.cpp b/src/lib/block/safer/safer_sk.cpp new file mode 100644 index 000000000..3e93ab8cf --- /dev/null +++ b/src/lib/block/safer/safer_sk.cpp @@ -0,0 +1,256 @@ +/* +* SAFER-SK +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const byte EXP[256] = { + 0x01, 0x2D, 0xE2, 0x93, 0xBE, 0x45, 0x15, 0xAE, 0x78, 0x03, 0x87, 0xA4, + 0xB8, 0x38, 0xCF, 0x3F, 0x08, 0x67, 0x09, 0x94, 0xEB, 0x26, 0xA8, 0x6B, + 0xBD, 0x18, 0x34, 0x1B, 0xBB, 0xBF, 0x72, 0xF7, 0x40, 0x35, 0x48, 0x9C, + 0x51, 0x2F, 0x3B, 0x55, 0xE3, 0xC0, 0x9F, 0xD8, 0xD3, 0xF3, 0x8D, 0xB1, + 0xFF, 0xA7, 0x3E, 0xDC, 0x86, 0x77, 0xD7, 0xA6, 0x11, 0xFB, 0xF4, 0xBA, + 0x92, 0x91, 0x64, 0x83, 0xF1, 0x33, 0xEF, 0xDA, 0x2C, 0xB5, 0xB2, 0x2B, + 0x88, 0xD1, 0x99, 0xCB, 0x8C, 0x84, 0x1D, 0x14, 0x81, 0x97, 0x71, 0xCA, + 0x5F, 0xA3, 0x8B, 0x57, 0x3C, 0x82, 0xC4, 0x52, 0x5C, 0x1C, 0xE8, 0xA0, + 0x04, 0xB4, 0x85, 0x4A, 0xF6, 0x13, 0x54, 0xB6, 0xDF, 0x0C, 0x1A, 0x8E, + 0xDE, 0xE0, 0x39, 0xFC, 0x20, 0x9B, 0x24, 0x4E, 0xA9, 0x98, 0x9E, 0xAB, + 0xF2, 0x60, 0xD0, 0x6C, 0xEA, 0xFA, 0xC7, 0xD9, 0x00, 0xD4, 0x1F, 0x6E, + 0x43, 0xBC, 0xEC, 0x53, 0x89, 0xFE, 0x7A, 0x5D, 0x49, 0xC9, 0x32, 0xC2, + 0xF9, 0x9A, 0xF8, 0x6D, 0x16, 0xDB, 0x59, 0x96, 0x44, 0xE9, 0xCD, 0xE6, + 0x46, 0x42, 0x8F, 0x0A, 0xC1, 0xCC, 0xB9, 0x65, 0xB0, 0xD2, 0xC6, 0xAC, + 0x1E, 0x41, 0x62, 0x29, 0x2E, 0x0E, 0x74, 0x50, 0x02, 0x5A, 0xC3, 0x25, + 0x7B, 0x8A, 0x2A, 0x5B, 0xF0, 0x06, 0x0D, 0x47, 0x6F, 0x70, 0x9D, 0x7E, + 0x10, 0xCE, 0x12, 0x27, 0xD5, 0x4C, 0x4F, 0xD6, 0x79, 0x30, 0x68, 0x36, + 0x75, 0x7D, 0xE4, 0xED, 0x80, 0x6A, 0x90, 0x37, 0xA2, 0x5E, 0x76, 0xAA, + 0xC5, 0x7F, 0x3D, 0xAF, 0xA5, 0xE5, 0x19, 0x61, 0xFD, 0x4D, 0x7C, 0xB7, + 0x0B, 0xEE, 0xAD, 0x4B, 0x22, 0xF5, 0xE7, 0x73, 0x23, 0x21, 0xC8, 0x05, + 0xE1, 0x66, 0xDD, 0xB3, 0x58, 0x69, 0x63, 0x56, 0x0F, 0xA1, 0x31, 0x95, + 0x17, 0x07, 0x3A, 0x28 }; + +const byte LOG[512] = { + 0x80, 0x00, 0xB0, 0x09, 0x60, 0xEF, 0xB9, 0xFD, 0x10, 0x12, 0x9F, 0xE4, + 0x69, 0xBA, 0xAD, 0xF8, 0xC0, 0x38, 0xC2, 0x65, 0x4F, 0x06, 0x94, 0xFC, + 0x19, 0xDE, 0x6A, 0x1B, 0x5D, 0x4E, 0xA8, 0x82, 0x70, 0xED, 0xE8, 0xEC, + 0x72, 0xB3, 0x15, 0xC3, 0xFF, 0xAB, 0xB6, 0x47, 0x44, 0x01, 0xAC, 0x25, + 0xC9, 0xFA, 0x8E, 0x41, 0x1A, 0x21, 0xCB, 0xD3, 0x0D, 0x6E, 0xFE, 0x26, + 0x58, 0xDA, 0x32, 0x0F, 0x20, 0xA9, 0x9D, 0x84, 0x98, 0x05, 0x9C, 0xBB, + 0x22, 0x8C, 0x63, 0xE7, 0xC5, 0xE1, 0x73, 0xC6, 0xAF, 0x24, 0x5B, 0x87, + 0x66, 0x27, 0xF7, 0x57, 0xF4, 0x96, 0xB1, 0xB7, 0x5C, 0x8B, 0xD5, 0x54, + 0x79, 0xDF, 0xAA, 0xF6, 0x3E, 0xA3, 0xF1, 0x11, 0xCA, 0xF5, 0xD1, 0x17, + 0x7B, 0x93, 0x83, 0xBC, 0xBD, 0x52, 0x1E, 0xEB, 0xAE, 0xCC, 0xD6, 0x35, + 0x08, 0xC8, 0x8A, 0xB4, 0xE2, 0xCD, 0xBF, 0xD9, 0xD0, 0x50, 0x59, 0x3F, + 0x4D, 0x62, 0x34, 0x0A, 0x48, 0x88, 0xB5, 0x56, 0x4C, 0x2E, 0x6B, 0x9E, + 0xD2, 0x3D, 0x3C, 0x03, 0x13, 0xFB, 0x97, 0x51, 0x75, 0x4A, 0x91, 0x71, + 0x23, 0xBE, 0x76, 0x2A, 0x5F, 0xF9, 0xD4, 0x55, 0x0B, 0xDC, 0x37, 0x31, + 0x16, 0x74, 0xD7, 0x77, 0xA7, 0xE6, 0x07, 0xDB, 0xA4, 0x2F, 0x46, 0xF3, + 0x61, 0x45, 0x67, 0xE3, 0x0C, 0xA2, 0x3B, 0x1C, 0x85, 0x18, 0x04, 0x1D, + 0x29, 0xA0, 0x8F, 0xB2, 0x5A, 0xD8, 0xA6, 0x7E, 0xEE, 0x8D, 0x53, 0x4B, + 0xA1, 0x9A, 0xC1, 0x0E, 0x7A, 0x49, 0xA5, 0x2C, 0x81, 0xC4, 0xC7, 0x36, + 0x2B, 0x7F, 0x43, 0x95, 0x33, 0xF2, 0x6C, 0x68, 0x6D, 0xF0, 0x02, 0x28, + 0xCE, 0xDD, 0x9B, 0xEA, 0x5E, 0x99, 0x7C, 0x14, 0x86, 0xCF, 0xE5, 0x42, + 0xB8, 0x40, 0x78, 0x2D, 0x3A, 0xE9, 0x64, 0x1F, 0x92, 0x90, 0x7D, 0x39, + 0x6F, 0xE0, 0x89, 0x30, 0x80, 0x00, 0xB0, 0x09, 0x60, 0xEF, 0xB9, 0xFD, + 0x10, 0x12, 0x9F, 0xE4, 0x69, 0xBA, 0xAD, 0xF8, 0xC0, 0x38, 0xC2, 0x65, + 0x4F, 0x06, 0x94, 0xFC, 0x19, 0xDE, 0x6A, 0x1B, 0x5D, 0x4E, 0xA8, 0x82, + 0x70, 0xED, 0xE8, 0xEC, 0x72, 0xB3, 0x15, 0xC3, 0xFF, 0xAB, 0xB6, 0x47, + 0x44, 0x01, 0xAC, 0x25, 0xC9, 0xFA, 0x8E, 0x41, 0x1A, 0x21, 0xCB, 0xD3, + 0x0D, 0x6E, 0xFE, 0x26, 0x58, 0xDA, 0x32, 0x0F, 0x20, 0xA9, 0x9D, 0x84, + 0x98, 0x05, 0x9C, 0xBB, 0x22, 0x8C, 0x63, 0xE7, 0xC5, 0xE1, 0x73, 0xC6, + 0xAF, 0x24, 0x5B, 0x87, 0x66, 0x27, 0xF7, 0x57, 0xF4, 0x96, 0xB1, 0xB7, + 0x5C, 0x8B, 0xD5, 0x54, 0x79, 0xDF, 0xAA, 0xF6, 0x3E, 0xA3, 0xF1, 0x11, + 0xCA, 0xF5, 0xD1, 0x17, 0x7B, 0x93, 0x83, 0xBC, 0xBD, 0x52, 0x1E, 0xEB, + 0xAE, 0xCC, 0xD6, 0x35, 0x08, 0xC8, 0x8A, 0xB4, 0xE2, 0xCD, 0xBF, 0xD9, + 0xD0, 0x50, 0x59, 0x3F, 0x4D, 0x62, 0x34, 0x0A, 0x48, 0x88, 0xB5, 0x56, + 0x4C, 0x2E, 0x6B, 0x9E, 0xD2, 0x3D, 0x3C, 0x03, 0x13, 0xFB, 0x97, 0x51, + 0x75, 0x4A, 0x91, 0x71, 0x23, 0xBE, 0x76, 0x2A, 0x5F, 0xF9, 0xD4, 0x55, + 0x0B, 0xDC, 0x37, 0x31, 0x16, 0x74, 0xD7, 0x77, 0xA7, 0xE6, 0x07, 0xDB, + 0xA4, 0x2F, 0x46, 0xF3, 0x61, 0x45, 0x67, 0xE3, 0x0C, 0xA2, 0x3B, 0x1C, + 0x85, 0x18, 0x04, 0x1D, 0x29, 0xA0, 0x8F, 0xB2, 0x5A, 0xD8, 0xA6, 0x7E, + 0xEE, 0x8D, 0x53, 0x4B, 0xA1, 0x9A, 0xC1, 0x0E, 0x7A, 0x49, 0xA5, 0x2C, + 0x81, 0xC4, 0xC7, 0x36, 0x2B, 0x7F, 0x43, 0x95, 0x33, 0xF2, 0x6C, 0x68, + 0x6D, 0xF0, 0x02, 0x28, 0xCE, 0xDD, 0x9B, 0xEA, 0x5E, 0x99, 0x7C, 0x14, + 0x86, 0xCF, 0xE5, 0x42, 0xB8, 0x40, 0x78, 0x2D, 0x3A, 0xE9, 0x64, 0x1F, + 0x92, 0x90, 0x7D, 0x39, 0x6F, 0xE0, 0x89, 0x30 }; + +} + +/* +* SAFER-SK Encryption +*/ +void SAFER_SK::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + byte A = in[0], B = in[1], C = in[2], D = in[3], + E = in[4], F = in[5], G = in[6], H = in[7], X, Y; + + for(size_t j = 0; j != 16*rounds; j += 16) + { + A = EXP[A ^ EK[j ]]; B = LOG[B + EK[j+1]]; + C = LOG[C + EK[j+2]]; D = EXP[D ^ EK[j+3]]; + E = EXP[E ^ EK[j+4]]; F = LOG[F + EK[j+5]]; + G = LOG[G + EK[j+6]]; H = EXP[H ^ EK[j+7]]; + + A += EK[j+ 8]; B ^= EK[j+ 9]; C ^= EK[j+10]; D += EK[j+11]; + E += EK[j+12]; F ^= EK[j+13]; G ^= EK[j+14]; H += EK[j+15]; + + B += A; D += C; F += E; H += G; A += B; C += D; E += F; G += H; + C += A; G += E; D += B; H += F; A += C; E += G; B += D; F += H; + H += D; Y = D + H; D = B + F; X = B + D; B = A + E; + A += B; F = C + G; E = C + F; C = X; G = Y; + } + + out[0] = A ^ EK[16*rounds+0]; out[1] = B + EK[16*rounds+1]; + out[2] = C + EK[16*rounds+2]; out[3] = D ^ EK[16*rounds+3]; + out[4] = E ^ EK[16*rounds+4]; out[5] = F + EK[16*rounds+5]; + out[6] = G + EK[16*rounds+6]; out[7] = H ^ EK[16*rounds+7]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SAFER-SK Decryption +*/ +void SAFER_SK::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + byte A = in[0], B = in[1], C = in[2], D = in[3], + E = in[4], F = in[5], G = in[6], H = in[7]; + + A ^= EK[16*rounds+0]; B -= EK[16*rounds+1]; C -= EK[16*rounds+2]; + D ^= EK[16*rounds+3]; E ^= EK[16*rounds+4]; F -= EK[16*rounds+5]; + G -= EK[16*rounds+6]; H ^= EK[16*rounds+7]; + + for(s32bit j = 16*(rounds-1); j >= 0; j -= 16) + { + byte T = E; E = B; B = C; C = T; T = F; F = D; D = G; G = T; + A -= E; B -= F; C -= G; D -= H; E -= A; F -= B; G -= C; H -= D; + A -= C; E -= G; B -= D; F -= H; C -= A; G -= E; D -= B; H -= F; + A -= B; C -= D; E -= F; G -= H; B -= A; D -= C; F -= E; H -= G; + + A = LOG[A - EK[j+8 ] + 256]; B = EXP[B ^ EK[j+9 ]]; + C = EXP[C ^ EK[j+10]]; D = LOG[D - EK[j+11] + 256]; + E = LOG[E - EK[j+12] + 256]; F = EXP[F ^ EK[j+13]]; + G = EXP[G ^ EK[j+14]]; H = LOG[H - EK[j+15] + 256]; + + A ^= EK[j+0]; B -= EK[j+1]; C -= EK[j+2]; D ^= EK[j+3]; + E ^= EK[j+4]; F -= EK[j+5]; G -= EK[j+6]; H ^= EK[j+7]; + } + + out[0] = A; out[1] = B; out[2] = C; out[3] = D; + out[4] = E; out[5] = F; out[6] = G; out[7] = H; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SAFER-SK Key Schedule +*/ +void SAFER_SK::key_schedule(const byte key[], size_t) + { + const byte BIAS[208] = { + 0x16, 0x73, 0x3B, 0x1E, 0x8E, 0x70, 0xBD, 0x86, 0x47, 0x7E, 0x24, 0x56, + 0xF1, 0x77, 0x88, 0x46, 0xB1, 0xBA, 0xA3, 0xB7, 0x10, 0x0A, 0xC5, 0x37, + 0xC9, 0x5A, 0x28, 0xAC, 0x64, 0xA5, 0xEC, 0xAB, 0xC6, 0x67, 0x95, 0x58, + 0x0D, 0xF8, 0x9A, 0xF6, 0x66, 0xDC, 0x05, 0x3D, 0xD3, 0x8A, 0xC3, 0xD8, + 0x6A, 0xE9, 0x36, 0x49, 0x43, 0xBF, 0xEB, 0xD4, 0x9B, 0x68, 0xA0, 0x65, + 0x5D, 0x57, 0x92, 0x1F, 0x71, 0x5C, 0xBB, 0x22, 0xC1, 0xBE, 0x7B, 0xBC, + 0x63, 0x94, 0x5F, 0x2A, 0x61, 0xB8, 0x34, 0x32, 0xFD, 0xFB, 0x17, 0x40, + 0xE6, 0x51, 0x1D, 0x41, 0x8F, 0x29, 0xDD, 0x04, 0x80, 0xDE, 0xE7, 0x31, + 0x7F, 0x01, 0xA2, 0xF7, 0x39, 0xDA, 0x6F, 0x23, 0xFE, 0x3A, 0xD0, 0x1C, + 0xD1, 0x30, 0x3E, 0x12, 0xCD, 0x0F, 0xE0, 0xA8, 0xAF, 0x82, 0x59, 0x2C, + 0x7D, 0xAD, 0xB2, 0xEF, 0xC2, 0x87, 0xCE, 0x75, 0x13, 0x02, 0x90, 0x4F, + 0x2E, 0x72, 0x33, 0x85, 0x8D, 0xCF, 0xA9, 0x81, 0xE2, 0xC4, 0x27, 0x2F, + 0x7A, 0x9F, 0x52, 0xE1, 0x15, 0x38, 0x2B, 0xFC, 0x42, 0xC7, 0x08, 0xE4, + 0x09, 0x55, 0x5E, 0x8C, 0x76, 0x60, 0xFF, 0xDF, 0xD7, 0x98, 0xFA, 0x0B, + 0x00, 0x1A, 0xF9, 0xA6, 0xB9, 0xE8, 0x9E, 0x62, 0xD9, 0x91, 0x50, 0xD2, + 0xEE, 0x18, 0xB4, 0x07, 0xEA, 0x5B, 0xA4, 0xC8, 0x0E, 0xCB, 0x48, 0x69, + 0x4E, 0x9C, 0x35, 0x79, 0x45, 0x4D, 0x54, 0xE5, 0x3C, 0x0C, 0x4A, 0x8B, + 0x3F, 0xCC, 0xA7, 0xDB }; + + const byte KEY_INDEX[208] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x09, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, + 0x00, 0x01, 0x02, 0x03, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x00, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, 0x02, 0x0E, 0x0F, 0x10, 0x11, + 0x09, 0x0A, 0x0B, 0x0C, 0x06, 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x08, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x09, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, + 0x00, 0x01, 0x02, 0x03, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F }; + + EK.resize(16 * rounds + 8); + + secure_vector KB(18); + + for(size_t i = 0; i != 8; ++i) + { + KB[ 8] ^= KB[i] = rotate_left(key[i], 5); + KB[17] ^= KB[i+9] = EK[i] = key[i+8]; + } + + for(size_t i = 0; i != rounds; ++i) + { + for(size_t j = 0; j != 18; ++j) + KB[j] = rotate_left(KB[j], 6); + for(size_t j = 0; j != 16; ++j) + EK[16*i+j+8] = KB[KEY_INDEX[16*i+j]] + BIAS[16*i+j]; + } + } + +void SAFER_SK::clear() + { + zap(EK); + } + +/* +* Return the name of this type +*/ +std::string SAFER_SK::name() const + { + return "SAFER-SK(" + std::to_string(rounds) + ")"; + } + +/* +* Return a clone of this object +*/ +BlockCipher* SAFER_SK::clone() const + { + return new SAFER_SK(rounds); + } + +/* +* SAFER-SK Constructor +*/ +SAFER_SK::SAFER_SK(size_t r) : rounds(r) + { + if(rounds > 13 || rounds == 0) + throw Invalid_Argument(name() + ": Invalid number of rounds"); + } + +} diff --git a/src/lib/block/safer/safer_sk.h b/src/lib/block/safer/safer_sk.h new file mode 100644 index 000000000..043ecb456 --- /dev/null +++ b/src/lib/block/safer/safer_sk.h @@ -0,0 +1,42 @@ +/* +* SAFER-SK +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SAFER_SK_H__ +#define BOTAN_SAFER_SK_H__ + +#include + +namespace Botan { + +/** +* SAFER-SK +*/ +class BOTAN_DLL SAFER_SK : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * @param rounds the number of rounds to use - must be between 1 + * and 13 + */ + SAFER_SK(size_t rounds); + private: + void key_schedule(const byte[], size_t); + + size_t rounds; + secure_vector EK; + }; + +} + +#endif diff --git a/src/lib/block/seed/info.txt b/src/lib/block/seed/info.txt new file mode 100644 index 000000000..1c6b28792 --- /dev/null +++ b/src/lib/block/seed/info.txt @@ -0,0 +1 @@ +define SEED 20131128 diff --git a/src/lib/block/seed/seed.cpp b/src/lib/block/seed/seed.cpp new file mode 100644 index 000000000..d133e4153 --- /dev/null +++ b/src/lib/block/seed/seed.cpp @@ -0,0 +1,146 @@ +/* +* SEED +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* SEED G Function +*/ +u32bit SEED::G_FUNC::operator()(u32bit X) const + { + return (S0[get_byte(3, X)] ^ S1[get_byte(2, X)] ^ + S2[get_byte(1, X)] ^ S3[get_byte(0, X)]); + } + +/* +* SEED Encryption +*/ +void SEED::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_be(in, 0); + u32bit B1 = load_be(in, 1); + u32bit B2 = load_be(in, 2); + u32bit B3 = load_be(in, 3); + + G_FUNC G; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit T0, T1; + + T0 = B2 ^ K[2*j]; + T1 = G(B2 ^ B3 ^ K[2*j+1]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B1 ^= T1; + B0 ^= T0 + T1; + + T0 = B0 ^ K[2*j+2]; + T1 = G(B0 ^ B1 ^ K[2*j+3]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B3 ^= T1; + B2 ^= T0 + T1; + } + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SEED Decryption +*/ +void SEED::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_be(in, 0); + u32bit B1 = load_be(in, 1); + u32bit B2 = load_be(in, 2); + u32bit B3 = load_be(in, 3); + + G_FUNC G; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit T0, T1; + + T0 = B2 ^ K[30-2*j]; + T1 = G(B2 ^ B3 ^ K[31-2*j]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B1 ^= T1; + B0 ^= T0 + T1; + + T0 = B0 ^ K[28-2*j]; + T1 = G(B0 ^ B1 ^ K[29-2*j]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B3 ^= T1; + B2 ^= T0 + T1; + } + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SEED Key Schedule +*/ +void SEED::key_schedule(const byte key[], size_t) + { + const u32bit RC[16] = { + 0x9E3779B9, 0x3C6EF373, 0x78DDE6E6, 0xF1BBCDCC, + 0xE3779B99, 0xC6EF3733, 0x8DDE6E67, 0x1BBCDCCF, + 0x3779B99E, 0x6EF3733C, 0xDDE6E678, 0xBBCDCCF1, + 0x779B99E3, 0xEF3733C6, 0xDE6E678D, 0xBCDCCF1B + }; + + secure_vector WK(4); + + for(size_t i = 0; i != 4; ++i) + WK[i] = load_be(key, i); + + G_FUNC G; + + K.resize(32); + + for(size_t i = 0; i != 16; i += 2) + { + K[2*i ] = G(WK[0] + WK[2] - RC[i]); + K[2*i+1] = G(WK[1] - WK[3] + RC[i]) ^ K[2*i]; + + byte T = get_byte(3, WK[0]); + WK[0] = (WK[0] >> 8) | (get_byte(3, WK[1]) << 24); + WK[1] = (WK[1] >> 8) | (T << 24); + + K[2*i+2] = G(WK[0] + WK[2] - RC[i+1]); + K[2*i+3] = G(WK[1] - WK[3] + RC[i+1]) ^ K[2*i+2]; + + T = get_byte(0, WK[3]); + WK[3] = (WK[3] << 8) | get_byte(0, WK[2]); + WK[2] = (WK[2] << 8) | T; + } + } + +void SEED::clear() + { + zap(K); + } + +} diff --git a/src/lib/block/seed/seed.h b/src/lib/block/seed/seed.h new file mode 100644 index 000000000..25138a700 --- /dev/null +++ b/src/lib/block/seed/seed.h @@ -0,0 +1,43 @@ +/* +* SEED +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SEED_H__ +#define BOTAN_SEED_H__ + +#include + +namespace Botan { + +/** +* SEED, a Korean block cipher +*/ +class BOTAN_DLL SEED : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "SEED"; } + BlockCipher* clone() const { return new SEED; } + private: + void key_schedule(const byte[], size_t); + + class G_FUNC + { + public: + u32bit operator()(u32bit) const; + private: + static const u32bit S0[256], S1[256], S2[256], S3[256]; + }; + + secure_vector K; + }; + +} + +#endif diff --git a/src/lib/block/seed/seed_tab.cpp b/src/lib/block/seed/seed_tab.cpp new file mode 100644 index 000000000..6ada36e52 --- /dev/null +++ b/src/lib/block/seed/seed_tab.cpp @@ -0,0 +1,192 @@ +/* +* S-Box Tables for SEED +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const u32bit SEED::G_FUNC::S0[256] = { + 0x2989A1A8, 0x05858184, 0x16C6D2D4, 0x13C3D3D0, 0x14445054, 0x1D0D111C, + 0x2C8CA0AC, 0x25052124, 0x1D4D515C, 0x03434340, 0x18081018, 0x1E0E121C, + 0x11415150, 0x3CCCF0FC, 0x0ACAC2C8, 0x23436360, 0x28082028, 0x04444044, + 0x20002020, 0x1D8D919C, 0x20C0E0E0, 0x22C2E2E0, 0x08C8C0C8, 0x17071314, + 0x2585A1A4, 0x0F8F838C, 0x03030300, 0x3B4B7378, 0x3B8BB3B8, 0x13031310, + 0x12C2D2D0, 0x2ECEE2EC, 0x30407070, 0x0C8C808C, 0x3F0F333C, 0x2888A0A8, + 0x32023230, 0x1DCDD1DC, 0x36C6F2F4, 0x34447074, 0x2CCCE0EC, 0x15859194, + 0x0B0B0308, 0x17475354, 0x1C4C505C, 0x1B4B5358, 0x3D8DB1BC, 0x01010100, + 0x24042024, 0x1C0C101C, 0x33437370, 0x18889098, 0x10001010, 0x0CCCC0CC, + 0x32C2F2F0, 0x19C9D1D8, 0x2C0C202C, 0x27C7E3E4, 0x32427270, 0x03838380, + 0x1B8B9398, 0x11C1D1D0, 0x06868284, 0x09C9C1C8, 0x20406060, 0x10405050, + 0x2383A3A0, 0x2BCBE3E8, 0x0D0D010C, 0x3686B2B4, 0x1E8E929C, 0x0F4F434C, + 0x3787B3B4, 0x1A4A5258, 0x06C6C2C4, 0x38487078, 0x2686A2A4, 0x12021210, + 0x2F8FA3AC, 0x15C5D1D4, 0x21416160, 0x03C3C3C0, 0x3484B0B4, 0x01414140, + 0x12425250, 0x3D4D717C, 0x0D8D818C, 0x08080008, 0x1F0F131C, 0x19899198, + 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37C7F3F4, 0x21C1E1E0, + 0x3DCDF1FC, 0x36467274, 0x2F0F232C, 0x27072324, 0x3080B0B0, 0x0B8B8388, + 0x0E0E020C, 0x2B8BA3A8, 0x2282A2A0, 0x2E4E626C, 0x13839390, 0x0D4D414C, + 0x29496168, 0x3C4C707C, 0x09090108, 0x0A0A0208, 0x3F8FB3BC, 0x2FCFE3EC, + 0x33C3F3F0, 0x05C5C1C4, 0x07878384, 0x14041014, 0x3ECEF2FC, 0x24446064, + 0x1ECED2DC, 0x2E0E222C, 0x0B4B4348, 0x1A0A1218, 0x06060204, 0x21012120, + 0x2B4B6368, 0x26466264, 0x02020200, 0x35C5F1F4, 0x12829290, 0x0A8A8288, + 0x0C0C000C, 0x3383B3B0, 0x3E4E727C, 0x10C0D0D0, 0x3A4A7278, 0x07474344, + 0x16869294, 0x25C5E1E4, 0x26062224, 0x00808080, 0x2D8DA1AC, 0x1FCFD3DC, + 0x2181A1A0, 0x30003030, 0x37073334, 0x2E8EA2AC, 0x36063234, 0x15051114, + 0x22022220, 0x38083038, 0x34C4F0F4, 0x2787A3A4, 0x05454144, 0x0C4C404C, + 0x01818180, 0x29C9E1E8, 0x04848084, 0x17879394, 0x35053134, 0x0BCBC3C8, + 0x0ECEC2CC, 0x3C0C303C, 0x31417170, 0x11011110, 0x07C7C3C4, 0x09898188, + 0x35457174, 0x3BCBF3F8, 0x1ACAD2D8, 0x38C8F0F8, 0x14849094, 0x19495158, + 0x02828280, 0x04C4C0C4, 0x3FCFF3FC, 0x09494148, 0x39093138, 0x27476364, + 0x00C0C0C0, 0x0FCFC3CC, 0x17C7D3D4, 0x3888B0B8, 0x0F0F030C, 0x0E8E828C, + 0x02424240, 0x23032320, 0x11819190, 0x2C4C606C, 0x1BCBD3D8, 0x2484A0A4, + 0x34043034, 0x31C1F1F0, 0x08484048, 0x02C2C2C0, 0x2F4F636C, 0x3D0D313C, + 0x2D0D212C, 0x00404040, 0x3E8EB2BC, 0x3E0E323C, 0x3C8CB0BC, 0x01C1C1C0, + 0x2A8AA2A8, 0x3A8AB2B8, 0x0E4E424C, 0x15455154, 0x3B0B3338, 0x1CCCD0DC, + 0x28486068, 0x3F4F737C, 0x1C8C909C, 0x18C8D0D8, 0x0A4A4248, 0x16465254, + 0x37477374, 0x2080A0A0, 0x2DCDE1EC, 0x06464244, 0x3585B1B4, 0x2B0B2328, + 0x25456164, 0x3ACAF2F8, 0x23C3E3E0, 0x3989B1B8, 0x3181B1B0, 0x1F8F939C, + 0x1E4E525C, 0x39C9F1F8, 0x26C6E2E4, 0x3282B2B0, 0x31013130, 0x2ACAE2E8, + 0x2D4D616C, 0x1F4F535C, 0x24C4E0E4, 0x30C0F0F0, 0x0DCDC1CC, 0x08888088, + 0x16061214, 0x3A0A3238, 0x18485058, 0x14C4D0D4, 0x22426260, 0x29092128, + 0x07070304, 0x33033330, 0x28C8E0E8, 0x1B0B1318, 0x05050104, 0x39497178, + 0x10809090, 0x2A4A6268, 0x2A0A2228, 0x1A8A9298 }; + +const u32bit SEED::G_FUNC::S1[256] = { + 0x38380830, 0xE828C8E0, 0x2C2D0D21, 0xA42686A2, 0xCC0FCFC3, 0xDC1ECED2, + 0xB03383B3, 0xB83888B0, 0xAC2F8FA3, 0x60204060, 0x54154551, 0xC407C7C3, + 0x44044440, 0x6C2F4F63, 0x682B4B63, 0x581B4B53, 0xC003C3C3, 0x60224262, + 0x30330333, 0xB43585B1, 0x28290921, 0xA02080A0, 0xE022C2E2, 0xA42787A3, + 0xD013C3D3, 0x90118191, 0x10110111, 0x04060602, 0x1C1C0C10, 0xBC3C8CB0, + 0x34360632, 0x480B4B43, 0xEC2FCFE3, 0x88088880, 0x6C2C4C60, 0xA82888A0, + 0x14170713, 0xC404C4C0, 0x14160612, 0xF434C4F0, 0xC002C2C2, 0x44054541, + 0xE021C1E1, 0xD416C6D2, 0x3C3F0F33, 0x3C3D0D31, 0x8C0E8E82, 0x98188890, + 0x28280820, 0x4C0E4E42, 0xF436C6F2, 0x3C3E0E32, 0xA42585A1, 0xF839C9F1, + 0x0C0D0D01, 0xDC1FCFD3, 0xD818C8D0, 0x282B0B23, 0x64264662, 0x783A4A72, + 0x24270723, 0x2C2F0F23, 0xF031C1F1, 0x70324272, 0x40024242, 0xD414C4D0, + 0x40014141, 0xC000C0C0, 0x70334373, 0x64274763, 0xAC2C8CA0, 0x880B8B83, + 0xF437C7F3, 0xAC2D8DA1, 0x80008080, 0x1C1F0F13, 0xC80ACAC2, 0x2C2C0C20, + 0xA82A8AA2, 0x34340430, 0xD012C2D2, 0x080B0B03, 0xEC2ECEE2, 0xE829C9E1, + 0x5C1D4D51, 0x94148490, 0x18180810, 0xF838C8F0, 0x54174753, 0xAC2E8EA2, + 0x08080800, 0xC405C5C1, 0x10130313, 0xCC0DCDC1, 0x84068682, 0xB83989B1, + 0xFC3FCFF3, 0x7C3D4D71, 0xC001C1C1, 0x30310131, 0xF435C5F1, 0x880A8A82, + 0x682A4A62, 0xB03181B1, 0xD011C1D1, 0x20200020, 0xD417C7D3, 0x00020202, + 0x20220222, 0x04040400, 0x68284860, 0x70314171, 0x04070703, 0xD81BCBD3, + 0x9C1D8D91, 0x98198991, 0x60214161, 0xBC3E8EB2, 0xE426C6E2, 0x58194951, + 0xDC1DCDD1, 0x50114151, 0x90108090, 0xDC1CCCD0, 0x981A8A92, 0xA02383A3, + 0xA82B8BA3, 0xD010C0D0, 0x80018181, 0x0C0F0F03, 0x44074743, 0x181A0A12, + 0xE023C3E3, 0xEC2CCCE0, 0x8C0D8D81, 0xBC3F8FB3, 0x94168692, 0x783B4B73, + 0x5C1C4C50, 0xA02282A2, 0xA02181A1, 0x60234363, 0x20230323, 0x4C0D4D41, + 0xC808C8C0, 0x9C1E8E92, 0x9C1C8C90, 0x383A0A32, 0x0C0C0C00, 0x2C2E0E22, + 0xB83A8AB2, 0x6C2E4E62, 0x9C1F8F93, 0x581A4A52, 0xF032C2F2, 0x90128292, + 0xF033C3F3, 0x48094941, 0x78384870, 0xCC0CCCC0, 0x14150511, 0xF83BCBF3, + 0x70304070, 0x74354571, 0x7C3F4F73, 0x34350531, 0x10100010, 0x00030303, + 0x64244460, 0x6C2D4D61, 0xC406C6C2, 0x74344470, 0xD415C5D1, 0xB43484B0, + 0xE82ACAE2, 0x08090901, 0x74364672, 0x18190911, 0xFC3ECEF2, 0x40004040, + 0x10120212, 0xE020C0E0, 0xBC3D8DB1, 0x04050501, 0xF83ACAF2, 0x00010101, + 0xF030C0F0, 0x282A0A22, 0x5C1E4E52, 0xA82989A1, 0x54164652, 0x40034343, + 0x84058581, 0x14140410, 0x88098981, 0x981B8B93, 0xB03080B0, 0xE425C5E1, + 0x48084840, 0x78394971, 0x94178793, 0xFC3CCCF0, 0x1C1E0E12, 0x80028282, + 0x20210121, 0x8C0C8C80, 0x181B0B13, 0x5C1F4F53, 0x74374773, 0x54144450, + 0xB03282B2, 0x1C1D0D11, 0x24250521, 0x4C0F4F43, 0x00000000, 0x44064642, + 0xEC2DCDE1, 0x58184850, 0x50124252, 0xE82BCBE3, 0x7C3E4E72, 0xD81ACAD2, + 0xC809C9C1, 0xFC3DCDF1, 0x30300030, 0x94158591, 0x64254561, 0x3C3C0C30, + 0xB43686B2, 0xE424C4E0, 0xB83B8BB3, 0x7C3C4C70, 0x0C0E0E02, 0x50104050, + 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393, + 0x34370733, 0xE427C7E3, 0x24240420, 0xA42484A0, 0xC80BCBC3, 0x50134353, + 0x080A0A02, 0x84078783, 0xD819C9D1, 0x4C0C4C40, 0x80038383, 0x8C0F8F83, + 0xCC0ECEC2, 0x383B0B33, 0x480A4A42, 0xB43787B3 }; + +const u32bit SEED::G_FUNC::S2[256] = { + 0xA1A82989, 0x81840585, 0xD2D416C6, 0xD3D013C3, 0x50541444, 0x111C1D0D, + 0xA0AC2C8C, 0x21242505, 0x515C1D4D, 0x43400343, 0x10181808, 0x121C1E0E, + 0x51501141, 0xF0FC3CCC, 0xC2C80ACA, 0x63602343, 0x20282808, 0x40440444, + 0x20202000, 0x919C1D8D, 0xE0E020C0, 0xE2E022C2, 0xC0C808C8, 0x13141707, + 0xA1A42585, 0x838C0F8F, 0x03000303, 0x73783B4B, 0xB3B83B8B, 0x13101303, + 0xD2D012C2, 0xE2EC2ECE, 0x70703040, 0x808C0C8C, 0x333C3F0F, 0xA0A82888, + 0x32303202, 0xD1DC1DCD, 0xF2F436C6, 0x70743444, 0xE0EC2CCC, 0x91941585, + 0x03080B0B, 0x53541747, 0x505C1C4C, 0x53581B4B, 0xB1BC3D8D, 0x01000101, + 0x20242404, 0x101C1C0C, 0x73703343, 0x90981888, 0x10101000, 0xC0CC0CCC, + 0xF2F032C2, 0xD1D819C9, 0x202C2C0C, 0xE3E427C7, 0x72703242, 0x83800383, + 0x93981B8B, 0xD1D011C1, 0x82840686, 0xC1C809C9, 0x60602040, 0x50501040, + 0xA3A02383, 0xE3E82BCB, 0x010C0D0D, 0xB2B43686, 0x929C1E8E, 0x434C0F4F, + 0xB3B43787, 0x52581A4A, 0xC2C406C6, 0x70783848, 0xA2A42686, 0x12101202, + 0xA3AC2F8F, 0xD1D415C5, 0x61602141, 0xC3C003C3, 0xB0B43484, 0x41400141, + 0x52501242, 0x717C3D4D, 0x818C0D8D, 0x00080808, 0x131C1F0F, 0x91981989, + 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xF3F437C7, 0xE1E021C1, + 0xF1FC3DCD, 0x72743646, 0x232C2F0F, 0x23242707, 0xB0B03080, 0x83880B8B, + 0x020C0E0E, 0xA3A82B8B, 0xA2A02282, 0x626C2E4E, 0x93901383, 0x414C0D4D, + 0x61682949, 0x707C3C4C, 0x01080909, 0x02080A0A, 0xB3BC3F8F, 0xE3EC2FCF, + 0xF3F033C3, 0xC1C405C5, 0x83840787, 0x10141404, 0xF2FC3ECE, 0x60642444, + 0xD2DC1ECE, 0x222C2E0E, 0x43480B4B, 0x12181A0A, 0x02040606, 0x21202101, + 0x63682B4B, 0x62642646, 0x02000202, 0xF1F435C5, 0x92901282, 0x82880A8A, + 0x000C0C0C, 0xB3B03383, 0x727C3E4E, 0xD0D010C0, 0x72783A4A, 0x43440747, + 0x92941686, 0xE1E425C5, 0x22242606, 0x80800080, 0xA1AC2D8D, 0xD3DC1FCF, + 0xA1A02181, 0x30303000, 0x33343707, 0xA2AC2E8E, 0x32343606, 0x11141505, + 0x22202202, 0x30383808, 0xF0F434C4, 0xA3A42787, 0x41440545, 0x404C0C4C, + 0x81800181, 0xE1E829C9, 0x80840484, 0x93941787, 0x31343505, 0xC3C80BCB, + 0xC2CC0ECE, 0x303C3C0C, 0x71703141, 0x11101101, 0xC3C407C7, 0x81880989, + 0x71743545, 0xF3F83BCB, 0xD2D81ACA, 0xF0F838C8, 0x90941484, 0x51581949, + 0x82800282, 0xC0C404C4, 0xF3FC3FCF, 0x41480949, 0x31383909, 0x63642747, + 0xC0C000C0, 0xC3CC0FCF, 0xD3D417C7, 0xB0B83888, 0x030C0F0F, 0x828C0E8E, + 0x42400242, 0x23202303, 0x91901181, 0x606C2C4C, 0xD3D81BCB, 0xA0A42484, + 0x30343404, 0xF1F031C1, 0x40480848, 0xC2C002C2, 0x636C2F4F, 0x313C3D0D, + 0x212C2D0D, 0x40400040, 0xB2BC3E8E, 0x323C3E0E, 0xB0BC3C8C, 0xC1C001C1, + 0xA2A82A8A, 0xB2B83A8A, 0x424C0E4E, 0x51541545, 0x33383B0B, 0xD0DC1CCC, + 0x60682848, 0x737C3F4F, 0x909C1C8C, 0xD0D818C8, 0x42480A4A, 0x52541646, + 0x73743747, 0xA0A02080, 0xE1EC2DCD, 0x42440646, 0xB1B43585, 0x23282B0B, + 0x61642545, 0xF2F83ACA, 0xE3E023C3, 0xB1B83989, 0xB1B03181, 0x939C1F8F, + 0x525C1E4E, 0xF1F839C9, 0xE2E426C6, 0xB2B03282, 0x31303101, 0xE2E82ACA, + 0x616C2D4D, 0x535C1F4F, 0xE0E424C4, 0xF0F030C0, 0xC1CC0DCD, 0x80880888, + 0x12141606, 0x32383A0A, 0x50581848, 0xD0D414C4, 0x62602242, 0x21282909, + 0x03040707, 0x33303303, 0xE0E828C8, 0x13181B0B, 0x01040505, 0x71783949, + 0x90901080, 0x62682A4A, 0x22282A0A, 0x92981A8A }; + +const u32bit SEED::G_FUNC::S3[256] = { + 0x08303838, 0xC8E0E828, 0x0D212C2D, 0x86A2A426, 0xCFC3CC0F, 0xCED2DC1E, + 0x83B3B033, 0x88B0B838, 0x8FA3AC2F, 0x40606020, 0x45515415, 0xC7C3C407, + 0x44404404, 0x4F636C2F, 0x4B63682B, 0x4B53581B, 0xC3C3C003, 0x42626022, + 0x03333033, 0x85B1B435, 0x09212829, 0x80A0A020, 0xC2E2E022, 0x87A3A427, + 0xC3D3D013, 0x81919011, 0x01111011, 0x06020406, 0x0C101C1C, 0x8CB0BC3C, + 0x06323436, 0x4B43480B, 0xCFE3EC2F, 0x88808808, 0x4C606C2C, 0x88A0A828, + 0x07131417, 0xC4C0C404, 0x06121416, 0xC4F0F434, 0xC2C2C002, 0x45414405, + 0xC1E1E021, 0xC6D2D416, 0x0F333C3F, 0x0D313C3D, 0x8E828C0E, 0x88909818, + 0x08202828, 0x4E424C0E, 0xC6F2F436, 0x0E323C3E, 0x85A1A425, 0xC9F1F839, + 0x0D010C0D, 0xCFD3DC1F, 0xC8D0D818, 0x0B23282B, 0x46626426, 0x4A72783A, + 0x07232427, 0x0F232C2F, 0xC1F1F031, 0x42727032, 0x42424002, 0xC4D0D414, + 0x41414001, 0xC0C0C000, 0x43737033, 0x47636427, 0x8CA0AC2C, 0x8B83880B, + 0xC7F3F437, 0x8DA1AC2D, 0x80808000, 0x0F131C1F, 0xCAC2C80A, 0x0C202C2C, + 0x8AA2A82A, 0x04303434, 0xC2D2D012, 0x0B03080B, 0xCEE2EC2E, 0xC9E1E829, + 0x4D515C1D, 0x84909414, 0x08101818, 0xC8F0F838, 0x47535417, 0x8EA2AC2E, + 0x08000808, 0xC5C1C405, 0x03131013, 0xCDC1CC0D, 0x86828406, 0x89B1B839, + 0xCFF3FC3F, 0x4D717C3D, 0xC1C1C001, 0x01313031, 0xC5F1F435, 0x8A82880A, + 0x4A62682A, 0x81B1B031, 0xC1D1D011, 0x00202020, 0xC7D3D417, 0x02020002, + 0x02222022, 0x04000404, 0x48606828, 0x41717031, 0x07030407, 0xCBD3D81B, + 0x8D919C1D, 0x89919819, 0x41616021, 0x8EB2BC3E, 0xC6E2E426, 0x49515819, + 0xCDD1DC1D, 0x41515011, 0x80909010, 0xCCD0DC1C, 0x8A92981A, 0x83A3A023, + 0x8BA3A82B, 0xC0D0D010, 0x81818001, 0x0F030C0F, 0x47434407, 0x0A12181A, + 0xC3E3E023, 0xCCE0EC2C, 0x8D818C0D, 0x8FB3BC3F, 0x86929416, 0x4B73783B, + 0x4C505C1C, 0x82A2A022, 0x81A1A021, 0x43636023, 0x03232023, 0x4D414C0D, + 0xC8C0C808, 0x8E929C1E, 0x8C909C1C, 0x0A32383A, 0x0C000C0C, 0x0E222C2E, + 0x8AB2B83A, 0x4E626C2E, 0x8F939C1F, 0x4A52581A, 0xC2F2F032, 0x82929012, + 0xC3F3F033, 0x49414809, 0x48707838, 0xCCC0CC0C, 0x05111415, 0xCBF3F83B, + 0x40707030, 0x45717435, 0x4F737C3F, 0x05313435, 0x00101010, 0x03030003, + 0x44606424, 0x4D616C2D, 0xC6C2C406, 0x44707434, 0xC5D1D415, 0x84B0B434, + 0xCAE2E82A, 0x09010809, 0x46727436, 0x09111819, 0xCEF2FC3E, 0x40404000, + 0x02121012, 0xC0E0E020, 0x8DB1BC3D, 0x05010405, 0xCAF2F83A, 0x01010001, + 0xC0F0F030, 0x0A22282A, 0x4E525C1E, 0x89A1A829, 0x46525416, 0x43434003, + 0x85818405, 0x04101414, 0x89818809, 0x8B93981B, 0x80B0B030, 0xC5E1E425, + 0x48404808, 0x49717839, 0x87939417, 0xCCF0FC3C, 0x0E121C1E, 0x82828002, + 0x01212021, 0x8C808C0C, 0x0B13181B, 0x4F535C1F, 0x47737437, 0x44505414, + 0x82B2B032, 0x0D111C1D, 0x05212425, 0x4F434C0F, 0x00000000, 0x46424406, + 0xCDE1EC2D, 0x48505818, 0x42525012, 0xCBE3E82B, 0x4E727C3E, 0xCAD2D81A, + 0xC9C1C809, 0xCDF1FC3D, 0x00303030, 0x85919415, 0x45616425, 0x0C303C3C, + 0x86B2B436, 0xC4E0E424, 0x8BB3B83B, 0x4C707C3C, 0x0E020C0E, 0x40505010, + 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013, + 0x07333437, 0xC7E3E427, 0x04202424, 0x84A0A424, 0xCBC3C80B, 0x43535013, + 0x0A02080A, 0x87838407, 0xC9D1D819, 0x4C404C0C, 0x83838003, 0x8F838C0F, + 0xCEC2CC0E, 0x0B33383B, 0x4A42480A, 0x87B3B437 }; + +} diff --git a/src/lib/block/serpent/info.txt b/src/lib/block/serpent/info.txt new file mode 100644 index 000000000..aa29c567f --- /dev/null +++ b/src/lib/block/serpent/info.txt @@ -0,0 +1,13 @@ +define SERPENT 20131128 + + +serpent.h + + + +serpent_sbox.h + + + +serpent.cpp + diff --git a/src/lib/block/serpent/serpent.cpp b/src/lib/block/serpent/serpent.cpp new file mode 100644 index 000000000..7b75d6b84 --- /dev/null +++ b/src/lib/block/serpent/serpent.cpp @@ -0,0 +1,205 @@ +/* +* Serpent +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Serpent's Linear Transformation +*/ +inline void transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + B0 = rotate_left(B0, 13); B2 = rotate_left(B2, 3); + B1 ^= B0 ^ B2; B3 ^= B2 ^ (B0 << 3); + B1 = rotate_left(B1, 1); B3 = rotate_left(B3, 7); + B0 ^= B1 ^ B3; B2 ^= B3 ^ (B1 << 7); + B0 = rotate_left(B0, 5); B2 = rotate_left(B2, 22); + } + +/* +* Serpent's Inverse Linear Transformation +*/ +inline void i_transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + B2 = rotate_right(B2, 22); B0 = rotate_right(B0, 5); + B2 ^= B3 ^ (B1 << 7); B0 ^= B1 ^ B3; + B3 = rotate_right(B3, 7); B1 = rotate_right(B1, 1); + B3 ^= B2 ^ (B0 << 3); B1 ^= B0 ^ B2; + B2 = rotate_right(B2, 3); B0 = rotate_right(B0, 13); + } + +} + +/* +* XOR a key block with a data block +*/ +#define key_xor(round, B0, B1, B2, B3) \ + B0 ^= round_key[4*round ]; \ + B1 ^= round_key[4*round+1]; \ + B2 ^= round_key[4*round+2]; \ + B3 ^= round_key[4*round+3]; + +/* +* Serpent Encryption +*/ +void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_le(in, 0); + u32bit B1 = load_le(in, 1); + u32bit B2 = load_le(in, 2); + u32bit B3 = load_le(in, 3); + + key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + store_le(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Serpent Decryption +*/ +void Serpent::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_le(in, 0); + u32bit B1 = load_le(in, 1); + u32bit B2 = load_le(in, 2); + u32bit B3 = load_le(in, 3); + + key_xor(32,B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + store_le(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +#undef key_xor +#undef transform +#undef i_transform + +/* +* Serpent Key Schedule +*/ +void Serpent::key_schedule(const byte key[], size_t length) + { + const u32bit PHI = 0x9E3779B9; + + secure_vector W(140); + for(size_t i = 0; i != length / 4; ++i) + W[i] = load_le(key, i); + + W[length / 4] |= u32bit(1) << ((length%4)*8); + + for(size_t i = 8; i != 140; ++i) + { + u32bit wi = W[i-8] ^ W[i-5] ^ W[i-3] ^ W[i-1] ^ PHI ^ u32bit(i-8); + W[i] = rotate_left(wi, 11); + } + + SBoxE4(W[ 8],W[ 9],W[ 10],W[ 11]); SBoxE3(W[ 12],W[ 13],W[ 14],W[ 15]); + SBoxE2(W[ 16],W[ 17],W[ 18],W[ 19]); SBoxE1(W[ 20],W[ 21],W[ 22],W[ 23]); + SBoxE8(W[ 24],W[ 25],W[ 26],W[ 27]); SBoxE7(W[ 28],W[ 29],W[ 30],W[ 31]); + SBoxE6(W[ 32],W[ 33],W[ 34],W[ 35]); SBoxE5(W[ 36],W[ 37],W[ 38],W[ 39]); + SBoxE4(W[ 40],W[ 41],W[ 42],W[ 43]); SBoxE3(W[ 44],W[ 45],W[ 46],W[ 47]); + SBoxE2(W[ 48],W[ 49],W[ 50],W[ 51]); SBoxE1(W[ 52],W[ 53],W[ 54],W[ 55]); + SBoxE8(W[ 56],W[ 57],W[ 58],W[ 59]); SBoxE7(W[ 60],W[ 61],W[ 62],W[ 63]); + SBoxE6(W[ 64],W[ 65],W[ 66],W[ 67]); SBoxE5(W[ 68],W[ 69],W[ 70],W[ 71]); + SBoxE4(W[ 72],W[ 73],W[ 74],W[ 75]); SBoxE3(W[ 76],W[ 77],W[ 78],W[ 79]); + SBoxE2(W[ 80],W[ 81],W[ 82],W[ 83]); SBoxE1(W[ 84],W[ 85],W[ 86],W[ 87]); + SBoxE8(W[ 88],W[ 89],W[ 90],W[ 91]); SBoxE7(W[ 92],W[ 93],W[ 94],W[ 95]); + SBoxE6(W[ 96],W[ 97],W[ 98],W[ 99]); SBoxE5(W[100],W[101],W[102],W[103]); + SBoxE4(W[104],W[105],W[106],W[107]); SBoxE3(W[108],W[109],W[110],W[111]); + SBoxE2(W[112],W[113],W[114],W[115]); SBoxE1(W[116],W[117],W[118],W[119]); + SBoxE8(W[120],W[121],W[122],W[123]); SBoxE7(W[124],W[125],W[126],W[127]); + SBoxE6(W[128],W[129],W[130],W[131]); SBoxE5(W[132],W[133],W[134],W[135]); + SBoxE4(W[136],W[137],W[138],W[139]); + + round_key.assign(&W[8], &W[140]); + } + +void Serpent::clear() + { + zap(round_key); + } + +} diff --git a/src/lib/block/serpent/serpent.h b/src/lib/block/serpent/serpent.h new file mode 100644 index 000000000..dc539c9f3 --- /dev/null +++ b/src/lib/block/serpent/serpent.h @@ -0,0 +1,51 @@ +/* +* Serpent +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SERPENT_H__ +#define BOTAN_SERPENT_H__ + +#include + +namespace Botan { + +/** +* Serpent, an AES finalist +*/ +class BOTAN_DLL Serpent : public Block_Cipher_Fixed_Params<16, 16, 32, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Serpent"; } + BlockCipher* clone() const { return new Serpent; } + protected: + /** + * For use by subclasses using SIMD, asm, etc + * @return const reference to the key schedule + */ + const secure_vector& get_round_keys() const + { return round_key; } + + /** + * For use by subclasses that implement the key schedule + * @param ks is the new key schedule value to set + */ + void set_round_keys(const u32bit ks[132]) + { + round_key.assign(&ks[0], &ks[132]); + } + + private: + void key_schedule(const byte key[], size_t length); + secure_vector round_key; + }; + +} + +#endif diff --git a/src/lib/block/serpent/serpent_sbox.h b/src/lib/block/serpent/serpent_sbox.h new file mode 100644 index 000000000..fb396120e --- /dev/null +++ b/src/lib/block/serpent/serpent_sbox.h @@ -0,0 +1,428 @@ +/* +* Serpent SBox Expressions +* (C) 1999-2007,2013 Jack Lloyd +* +* The sbox expressions used here were discovered by Dag Arne Osvik and +* are described in his paper "Speeding Up Serpent". +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SERPENT_SBOX_H__ +#define BOTAN_SERPENT_SBOX_H__ + +#define SBoxE1(B0, B1, B2, B3) \ + do { \ + B3 ^= B0; \ + auto B4 = B1; \ + B1 &= B3; \ + B4 ^= B2; \ + B1 ^= B0; \ + B0 |= B3; \ + B0 ^= B4; \ + B4 ^= B3; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 ^= B4; \ + B4 = ~B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B1 ^= B4; \ + B3 |= B0; \ + B1 ^= B3; \ + B4 ^= B3; \ + B3 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE2(B0, B1, B2, B3) \ + do { \ + B0 = ~B0; \ + B2 = ~B2; \ + auto B4 = B0; \ + B0 &= B1; \ + B2 ^= B0; \ + B0 |= B3; \ + B3 ^= B2; \ + B1 ^= B0; \ + B0 ^= B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B2 |= B0; \ + B2 &= B4; \ + B0 ^= B1; \ + B1 &= B2; \ + B1 ^= B0; \ + B0 &= B2; \ + B4 ^= B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE3(B0, B1, B2, B3) \ + do { \ + auto B4 = B0; \ + B0 &= B2; \ + B0 ^= B3; \ + B2 ^= B1; \ + B2 ^= B0; \ + B3 |= B4; \ + B3 ^= B1; \ + B4 ^= B2; \ + B1 = B3; \ + B3 |= B4; \ + B3 ^= B0; \ + B0 &= B1; \ + B4 ^= B0; \ + B1 ^= B3; \ + B1 ^= B4; \ + B0 = B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = ~B4; \ + } while(0); + +#define SBoxE4(B0, B1, B2, B3) \ + do { \ + auto B4 = B0; \ + B0 |= B3; \ + B3 ^= B1; \ + B1 &= B4; \ + B4 ^= B2; \ + B2 ^= B3; \ + B3 &= B0; \ + B4 |= B1; \ + B3 ^= B4; \ + B0 ^= B1; \ + B4 &= B0; \ + B1 ^= B3; \ + B4 ^= B2; \ + B1 |= B0; \ + B1 ^= B2; \ + B0 ^= B3; \ + B2 = B1; \ + B1 |= B3; \ + B0 ^= B1; \ + B1 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxE5(B0, B1, B2, B3) \ + do { \ + B1 ^= B3; \ + B3 = ~B3; \ + B2 ^= B3; \ + B3 ^= B0; \ + auto B4 = B1; \ + B1 &= B3; \ + B1 ^= B2; \ + B4 ^= B3; \ + B0 ^= B4; \ + B2 &= B4; \ + B2 ^= B0; \ + B0 &= B1; \ + B3 ^= B0; \ + B4 |= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B2 &= B3; \ + B0 = ~B0; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE6(B0, B1, B2, B3) \ + do { \ + B0 ^= B1; \ + B1 ^= B3; \ + B3 = ~B3; \ + auto B4 = B1; \ + B1 &= B0; \ + B2 ^= B3; \ + B1 ^= B2; \ + B2 |= B4; \ + B4 ^= B3; \ + B3 &= B1; \ + B3 ^= B0; \ + B4 ^= B1; \ + B4 ^= B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B2 = ~B2; \ + B0 ^= B4; \ + B4 |= B3; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxE7(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + auto B4 = B3; \ + B3 &= B0; \ + B0 ^= B4; \ + B3 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B2 ^= B0; \ + B0 |= B1; \ + B2 ^= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B4 ^= B3; \ + B4 ^= B0; \ + B3 = ~B3; \ + B2 &= B4; \ + B3 ^= B2; \ + B2 = B4; \ + } while(0); + +#define SBoxE8(B0, B1, B2, B3) \ + do { \ + auto B4 = B1; \ + B1 |= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B2 ^= B1; \ + B3 |= B4; \ + B3 &= B0; \ + B4 ^= B2; \ + B3 ^= B1; \ + B1 |= B4; \ + B1 ^= B0; \ + B0 |= B4; \ + B0 ^= B2; \ + B1 ^= B4; \ + B2 ^= B1; \ + B1 &= B0; \ + B1 ^= B4; \ + B2 = ~B2; \ + B2 |= B0; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = B0; \ + B0 = B4; \ + } while(0); + +#define SBoxD1(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + auto B4 = B1; \ + B1 |= B0; \ + B4 = ~B4; \ + B1 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B0 ^= B4; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 ^= B0; \ + B0 |= B1; \ + B0 ^= B2; \ + B3 ^= B4; \ + B2 ^= B1; \ + B3 ^= B0; \ + B3 ^= B1; \ + B2 &= B3; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxD2(B0, B1, B2, B3) \ + do { \ + auto B4 = B1; \ + B1 ^= B3; \ + B3 &= B1; \ + B4 ^= B2; \ + B3 ^= B0; \ + B0 |= B1; \ + B2 ^= B3; \ + B0 ^= B4; \ + B0 |= B2; \ + B1 ^= B3; \ + B0 ^= B1; \ + B1 |= B3; \ + B1 ^= B0; \ + B4 = ~B4; \ + B4 ^= B1; \ + B1 |= B0; \ + B1 ^= B0; \ + B1 |= B4; \ + B3 ^= B1; \ + B1 = B0; \ + B0 = B4; \ + B4 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD3(B0, B1, B2, B3) \ + do { \ + B2 ^= B3; \ + B3 ^= B0; \ + auto B4 = B3; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 |= B2; \ + B1 ^= B4; \ + B4 &= B3; \ + B2 ^= B3; \ + B4 &= B0; \ + B4 ^= B2; \ + B2 &= B1; \ + B2 |= B0; \ + B3 = ~B3; \ + B2 ^= B3; \ + B0 ^= B3; \ + B0 &= B1; \ + B3 ^= B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxD4(B0, B1, B2, B3) \ + do { \ + auto B4 = B2; \ + B2 ^= B1; \ + B0 ^= B2; \ + B4 &= B2; \ + B4 ^= B0; \ + B0 &= B1; \ + B1 ^= B3; \ + B3 |= B4; \ + B2 ^= B3; \ + B0 ^= B3; \ + B1 ^= B4; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 ^= B0; \ + B1 |= B2; \ + B0 ^= B3; \ + B1 ^= B4; \ + B0 ^= B1; \ + B4 = B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD5(B0, B1, B2, B3) \ + do { \ + auto B4 = B2; \ + B2 &= B3; \ + B2 ^= B1; \ + B1 |= B3; \ + B1 &= B0; \ + B4 ^= B2; \ + B4 ^= B1; \ + B1 &= B2; \ + B0 = ~B0; \ + B3 ^= B4; \ + B1 ^= B3; \ + B3 &= B0; \ + B3 ^= B2; \ + B0 ^= B1; \ + B2 &= B0; \ + B3 ^= B0; \ + B2 ^= B4; \ + B2 |= B3; \ + B3 ^= B0; \ + B2 ^= B1; \ + B1 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD6(B0, B1, B2, B3) \ + do { \ + B1 = ~B1; \ + auto B4 = B3; \ + B2 ^= B1; \ + B3 |= B0; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 ^= B4; \ + B4 |= B0; \ + B4 ^= B1; \ + B1 &= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B3 &= B4; \ + B4 ^= B1; \ + B3 ^= B4; \ + B4 = ~B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + B4 = B3; \ + B3 = B2; \ + B2 = B4; \ + } while(0); + +#define SBoxD7(B0, B1, B2, B3) \ + do { \ + B0 ^= B2; \ + auto B4 = B2; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B2 ^= B3; \ + B4 |= B0; \ + B0 ^= B2; \ + B3 ^= B4; \ + B4 ^= B1; \ + B1 &= B3; \ + B1 ^= B0; \ + B0 ^= B3; \ + B0 |= B2; \ + B3 ^= B1; \ + B4 ^= B0; \ + B0 = B1; \ + B1 = B2; \ + B2 = B4; \ + } while(0); + +#define SBoxD8(B0, B1, B2, B3) \ + do { \ + auto B4 = B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 |= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B1 |= B0; \ + B0 ^= B2; \ + B2 &= B4; \ + B3 &= B4; \ + B1 ^= B2; \ + B2 ^= B0; \ + B0 |= B2; \ + B4 ^= B1; \ + B0 ^= B3; \ + B3 ^= B4; \ + B4 |= B0; \ + B3 ^= B2; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B0; \ + B0 = B3; \ + B3 = B4; \ + } while(0); + +#endif diff --git a/src/lib/block/serpent_simd/info.txt b/src/lib/block/serpent_simd/info.txt new file mode 100644 index 000000000..f33548823 --- /dev/null +++ b/src/lib/block/serpent_simd/info.txt @@ -0,0 +1,15 @@ +define SERPENT_SIMD 20131128 + + +serpent +simd +simd_engine + + + +serp_simd.cpp + + + +serp_simd.h + diff --git a/src/lib/block/serpent_simd/serp_simd.cpp b/src/lib/block/serpent_simd/serp_simd.cpp new file mode 100644 index 000000000..bedf20122 --- /dev/null +++ b/src/lib/block/serpent_simd/serp_simd.cpp @@ -0,0 +1,216 @@ +/* +* Serpent (SIMD) +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +#define key_xor(round, B0, B1, B2, B3) \ + do { \ + B0 ^= SIMD_32(keys[4*round ]); \ + B1 ^= SIMD_32(keys[4*round+1]); \ + B2 ^= SIMD_32(keys[4*round+2]); \ + B3 ^= SIMD_32(keys[4*round+3]); \ + } while(0); + +/* +* Serpent's linear transformations +*/ +#define transform(B0, B1, B2, B3) \ + do { \ + B0.rotate_left(13); \ + B2.rotate_left(3); \ + B1 ^= B0 ^ B2; \ + B3 ^= B2 ^ (B0 << 3); \ + B1.rotate_left(1); \ + B3.rotate_left(7); \ + B0 ^= B1 ^ B3; \ + B2 ^= B3 ^ (B1 << 7); \ + B0.rotate_left(5); \ + B2.rotate_left(22); \ + } while(0); + +#define i_transform(B0, B1, B2, B3) \ + do { \ + B2.rotate_right(22); \ + B0.rotate_right(5); \ + B2 ^= B3 ^ (B1 << 7); \ + B0 ^= B1 ^ B3; \ + B3.rotate_right(7); \ + B1.rotate_right(1); \ + B3 ^= B2 ^ (B0 << 3); \ + B1 ^= B0 ^ B2; \ + B2.rotate_right(3); \ + B0.rotate_right(13); \ + } while(0); + +/* +* SIMD Serpent Encryption of 4 blocks in parallel +*/ +void serpent_encrypt_4(const byte in[64], + byte out[64], + const u32bit keys[132]) + { + SIMD_32 B0 = SIMD_32::load_le(in); + SIMD_32 B1 = SIMD_32::load_le(in + 16); + SIMD_32 B2 = SIMD_32::load_le(in + 32); + SIMD_32 B3 = SIMD_32::load_le(in + 48); + + SIMD_32::transpose(B0, B1, B2, B3); + + key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + SIMD_32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 16); + B2.store_le(out + 32); + B3.store_le(out + 48); + } + +/* +* SIMD Serpent Decryption of 4 blocks in parallel +*/ +void serpent_decrypt_4(const byte in[64], + byte out[64], + const u32bit keys[132]) + { + SIMD_32 B0 = SIMD_32::load_le(in); + SIMD_32 B1 = SIMD_32::load_le(in + 16); + SIMD_32 B2 = SIMD_32::load_le(in + 32); + SIMD_32 B3 = SIMD_32::load_le(in + 48); + + SIMD_32::transpose(B0, B1, B2, B3); + + key_xor(32,B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + SIMD_32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 16); + B2.store_le(out + 32); + B3.store_le(out + 48); + } + +} + +#undef key_xor +#undef transform +#undef i_transform + +/* +* Serpent Encryption +*/ +void Serpent_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_round_keys()[0]); + + while(blocks >= 4) + { + serpent_encrypt_4(in, out, KS); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + if(blocks) + Serpent::encrypt_n(in, out, blocks); + } + +/* +* Serpent Decryption +*/ +void Serpent_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_round_keys()[0]); + + while(blocks >= 4) + { + serpent_decrypt_4(in, out, KS); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + if(blocks) + Serpent::decrypt_n(in, out, blocks); + } + +} diff --git a/src/lib/block/serpent_simd/serp_simd.h b/src/lib/block/serpent_simd/serp_simd.h new file mode 100644 index 000000000..b3c0b06c8 --- /dev/null +++ b/src/lib/block/serpent_simd/serp_simd.h @@ -0,0 +1,31 @@ +/* +* Serpent (SIMD) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SERPENT_SIMD_H__ +#define BOTAN_SERPENT_SIMD_H__ + +#include + +namespace Botan { + +/** +* Serpent implementation using SIMD +*/ +class BOTAN_DLL Serpent_SIMD : public Serpent + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + BlockCipher* clone() const { return new Serpent_SIMD; } + }; + +} + +#endif diff --git a/src/lib/block/serpent_x86_32/info.txt b/src/lib/block/serpent_x86_32/info.txt new file mode 100644 index 000000000..370213e87 --- /dev/null +++ b/src/lib/block/serpent_x86_32/info.txt @@ -0,0 +1,12 @@ +define SERPENT_X86_32 20131128 + +load_on asm_ok + + +x86_32 + + + +asm_x86_32 +serpent + diff --git a/src/lib/block/serpent_x86_32/serp_x86_32.cpp b/src/lib/block/serpent_x86_32/serp_x86_32.cpp new file mode 100644 index 000000000..afff5835c --- /dev/null +++ b/src/lib/block/serpent_x86_32/serp_x86_32.cpp @@ -0,0 +1,88 @@ +/* +* Serpent in x86-32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +extern "C" { + +/** +* Entry point for Serpent encryption in x86 asm +* @param in the input block +* @param out the output block +* @param ks the key schedule +*/ +void botan_serpent_x86_32_encrypt(const byte in[16], + byte out[16], + const u32bit ks[132]); + +/** +* Entry point for Serpent decryption in x86 asm +* @param in the input block +* @param out the output block +* @param ks the key schedule +*/ +void botan_serpent_x86_32_decrypt(const byte in[16], + byte out[16], + const u32bit ks[132]); + +/** +* Entry point for Serpent key schedule in x86 asm +* @param ks holds the initial working key (padded), and is set to the + final key schedule +*/ +void botan_serpent_x86_32_key_schedule(u32bit ks[140]); + +} + +/* +* Serpent Encryption +*/ +void Serpent_X86_32::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + auto keys = this->get_round_keys(); + + for(size_t i = 0; i != blocks; ++i) + { + botan_serpent_x86_32_encrypt(in, out, &keys[0]); + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Serpent Decryption +*/ +void Serpent_X86_32::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + auto keys = this->get_round_keys(); + + for(size_t i = 0; i != blocks; ++i) + { + botan_serpent_x86_32_decrypt(in, out, &keys[0]); + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Serpent Key Schedule +*/ +void Serpent_X86_32::key_schedule(const byte key[], size_t length) + { + secure_vector W(140); + for(size_t i = 0; i != length / 4; ++i) + W[i] = load_le(key, i); + W[length / 4] |= u32bit(1) << ((length%4)*8); + + botan_serpent_x86_32_key_schedule(&W[0]); + this->set_round_keys(&W[8]); + } + +} diff --git a/src/lib/block/serpent_x86_32/serp_x86_32.h b/src/lib/block/serpent_x86_32/serp_x86_32.h new file mode 100644 index 000000000..f6c4d564a --- /dev/null +++ b/src/lib/block/serpent_x86_32/serp_x86_32.h @@ -0,0 +1,31 @@ +/* +* Serpent in x86-32 asm +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SERPENT_X86_32_H__ +#define BOTAN_SERPENT_X86_32_H__ + +#include + +namespace Botan { + +/** +* Serpent implementation in x86-32 assembly +*/ +class BOTAN_DLL Serpent_X86_32 : public Serpent + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + BlockCipher* clone() const { return new Serpent_X86_32; } + private: + void key_schedule(const byte[], size_t); + }; + +} + +#endif diff --git a/src/lib/block/serpent_x86_32/serp_x86_32_imp.S b/src/lib/block/serpent_x86_32/serp_x86_32_imp.S new file mode 100644 index 000000000..e2549a099 --- /dev/null +++ b/src/lib/block/serpent_x86_32/serp_x86_32_imp.S @@ -0,0 +1,669 @@ +/* +* Serpent in x86-32 assembler +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +START_LISTING(serp_x86_32.S) + +#define SBOX_E1(A, B, C, D, T) \ + XOR(D, A) ; \ + ASSIGN(T, B) ; \ + AND(B, D) ; \ + XOR(T, C) ; \ + XOR(B, A) ; \ + OR(A, D) ; \ + XOR(A, T) ; \ + XOR(T, D) ; \ + XOR(D, C) ; \ + OR(C, B) ; \ + XOR(C, T) ; \ + NOT(T) ; \ + OR(T, B) ; \ + XOR(B, D) ; \ + XOR(B, T) ; \ + OR(D, A) ; \ + XOR(B, D) ; \ + XOR(T, D) ; \ + ASSIGN(D, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, T) ; + +#define SBOX_E2(A, B, C, D, T) \ + NOT(A) ; \ + NOT(C) ; \ + ASSIGN(T, A) ; \ + AND(A, B) ; \ + XOR(C, A) ; \ + OR(A, D) ; \ + XOR(D, C) ; \ + XOR(B, A) ; \ + XOR(A, T) ; \ + OR(T, B) ; \ + XOR(B, D) ; \ + OR(C, A) ; \ + AND(C, T) ; \ + XOR(A, B) ; \ + AND(B, C) ; \ + XOR(B, A) ; \ + AND(A, C) ; \ + XOR(T, A) ; \ + ASSIGN(A, C) ; \ + ASSIGN(C, D) ; \ + ASSIGN(D, B) ; \ + ASSIGN(B, T) ; + +#define SBOX_E3(A, B, C, D, T) \ + ASSIGN(T, A) ; \ + AND(A, C) ; \ + XOR(A, D) ; \ + XOR(C, B) ; \ + XOR(C, A) ; \ + OR(D, T) ; \ + XOR(D, B) ; \ + XOR(T, C) ; \ + ASSIGN(B, D) ; \ + OR(D, T) ; \ + XOR(D, A) ; \ + AND(A, B) ; \ + XOR(T, A) ; \ + XOR(B, D) ; \ + XOR(B, T) ; \ + NOT(T) ; \ + ASSIGN(A, C) ; \ + ASSIGN(C, B) ; \ + ASSIGN(B, D) ; \ + ASSIGN(D, T) ; + +#define SBOX_E4(A, B, C, D, T) \ + ASSIGN(T, A) ; \ + OR(A, D) ; \ + XOR(D, B) ; \ + AND(B, T) ; \ + XOR(T, C) ; \ + XOR(C, D) ; \ + AND(D, A) ; \ + OR(T, B) ; \ + XOR(D, T) ; \ + XOR(A, B) ; \ + AND(T, A) ; \ + XOR(B, D) ; \ + XOR(T, C) ; \ + OR(B, A) ; \ + XOR(B, C) ; \ + XOR(A, D) ; \ + ASSIGN(C, B) ; \ + OR(B, D) ; \ + XOR(B, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, C) ; \ + ASSIGN(C, D) ; \ + ASSIGN(D, T) ; + +#define SBOX_E5(A, B, C, D, T) \ + XOR(B, D) ; \ + NOT(D) ; \ + XOR(C, D) ; \ + XOR(D, A) ; \ + ASSIGN(T, B) ; \ + AND(B, D) ; \ + XOR(B, C) ; \ + XOR(T, D) ; \ + XOR(A, T) ; \ + AND(C, T) ; \ + XOR(C, A) ; \ + AND(A, B) ; \ + XOR(D, A) ; \ + OR(T, B) ; \ + XOR(T, A) ; \ + OR(A, D) ; \ + XOR(A, C) ; \ + AND(C, D) ; \ + NOT(A) ; \ + XOR(T, C) ; \ + ASSIGN(C, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, T) ; + +#define SBOX_E6(A, B, C, D, T) \ + XOR(A, B) ; \ + XOR(B, D) ; \ + NOT(D) ; \ + ASSIGN(T, B) ; \ + AND(B, A) ; \ + XOR(C, D) ; \ + XOR(B, C) ; \ + OR(C, T) ; \ + XOR(T, D) ; \ + AND(D, B) ; \ + XOR(D, A) ; \ + XOR(T, B) ; \ + XOR(T, C) ; \ + XOR(C, A) ; \ + AND(A, D) ; \ + NOT(C) ; \ + XOR(A, T) ; \ + OR(T, D) ; \ + XOR(T, C) ; \ + ASSIGN(C, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, D) ; \ + ASSIGN(D, T) ; + +#define SBOX_E7(A, B, C, D, T) \ + NOT(C) ; \ + ASSIGN(T, D) ; \ + AND(D, A) ; \ + XOR(A, T) ; \ + XOR(D, C) ; \ + OR(C, T) ; \ + XOR(B, D) ; \ + XOR(C, A) ; \ + OR(A, B) ; \ + XOR(C, B) ; \ + XOR(T, A) ; \ + OR(A, D) ; \ + XOR(A, C) ; \ + XOR(T, D) ; \ + XOR(T, A) ; \ + NOT(D) ; \ + AND(C, T) ; \ + XOR(C, D) ; \ + ASSIGN(D, C) ; \ + ASSIGN(C, T) ; + +#define SBOX_E8(A, B, C, D, T) \ + ASSIGN(T, B) ; \ + OR(B, C) ; \ + XOR(B, D) ; \ + XOR(T, C) ; \ + XOR(C, B) ; \ + OR(D, T) ; \ + AND(D, A) ; \ + XOR(T, C) ; \ + XOR(D, B) ; \ + OR(B, T) ; \ + XOR(B, A) ; \ + OR(A, T) ; \ + XOR(A, C) ; \ + XOR(B, T) ; \ + XOR(C, B) ; \ + AND(B, A) ; \ + XOR(B, T) ; \ + NOT(C) ; \ + OR(C, A) ; \ + XOR(T, C) ; \ + ASSIGN(C, B) ; \ + ASSIGN(B, D) ; \ + ASSIGN(D, A) ; \ + ASSIGN(A, T) ; + +#define SBOX_D1(A, B, C, D, T) \ + NOT(C) ; \ + ASSIGN(T, B) ; \ + OR(B, A) ; \ + NOT(T) ; \ + XOR(B, C) ; \ + OR(C, T) ; \ + XOR(B, D) ; \ + XOR(A, T) ; \ + XOR(C, A) ; \ + AND(A, D) ; \ + XOR(T, A) ; \ + OR(A, B) ; \ + XOR(A, C) ; \ + XOR(D, T) ; \ + XOR(C, B) ; \ + XOR(D, A) ; \ + XOR(D, B) ; \ + AND(C, D) ; \ + XOR(T, C) ; \ + ASSIGN(C, B) ; \ + ASSIGN(B, T) ; + +#define SBOX_D2(A, B, C, D, T) \ + ASSIGN(T, B) ; \ + XOR(B, D) ; \ + AND(D, B) ; \ + XOR(T, C) ; \ + XOR(D, A) ; \ + OR(A, B) ; \ + XOR(C, D) ; \ + XOR(A, T) ; \ + OR(A, C) ; \ + XOR(B, D) ; \ + XOR(A, B) ; \ + OR(B, D) ; \ + XOR(B, A) ; \ + NOT(T) ; \ + XOR(T, B) ; \ + OR(B, A) ; \ + XOR(B, A) ; \ + OR(B, T) ; \ + XOR(D, B) ; \ + ASSIGN(B, A) ; \ + ASSIGN(A, T) ; \ + ASSIGN(T, D) ; \ + ASSIGN(D, C) ; \ + ASSIGN(C, T) ; + +#define SBOX_D3(A, B, C, D, T) \ + XOR(C, D) ; \ + XOR(D, A) ; \ + ASSIGN(T, D) ; \ + AND(D, C) ; \ + XOR(D, B) ; \ + OR(B, C) ; \ + XOR(B, T) ; \ + AND(T, D) ; \ + XOR(C, D) ; \ + AND(T, A) ; \ + XOR(T, C) ; \ + AND(C, B) ; \ + OR(C, A) ; \ + NOT(D) ; \ + XOR(C, D) ; \ + XOR(A, D) ; \ + AND(A, B) ; \ + XOR(D, T) ; \ + XOR(D, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, T) ; + +#define SBOX_D4(A, B, C, D, T) \ + ASSIGN(T, C) ; \ + XOR(C, B) ; \ + XOR(A, C) ; \ + AND(T, C) ; \ + XOR(T, A) ; \ + AND(A, B) ; \ + XOR(B, D) ; \ + OR(D, T) ; \ + XOR(C, D) ; \ + XOR(A, D) ; \ + XOR(B, T) ; \ + AND(D, C) ; \ + XOR(D, B) ; \ + XOR(B, A) ; \ + OR(B, C) ; \ + XOR(A, D) ; \ + XOR(B, T) ; \ + XOR(A, B) ; \ + ASSIGN(T, A) ; \ + ASSIGN(A, C) ; \ + ASSIGN(C, D) ; \ + ASSIGN(D, T) ; + +#define SBOX_D5(A, B, C, D, T) \ + ASSIGN(T, C) ; \ + AND(C, D) ; \ + XOR(C, B) ; \ + OR(B, D) ; \ + AND(B, A) ; \ + XOR(T, C) ; \ + XOR(T, B) ; \ + AND(B, C) ; \ + NOT(A) ; \ + XOR(D, T) ; \ + XOR(B, D) ; \ + AND(D, A) ; \ + XOR(D, C) ; \ + XOR(A, B) ; \ + AND(C, A) ; \ + XOR(D, A) ; \ + XOR(C, T) ; \ + OR(C, D) ; \ + XOR(D, A) ; \ + XOR(C, B) ; \ + ASSIGN(B, D) ; \ + ASSIGN(D, T) ; + +#define SBOX_D6(A, B, C, D, T) \ + NOT(B) ; \ + ASSIGN(T, D) ; \ + XOR(C, B) ; \ + OR(D, A) ; \ + XOR(D, C) ; \ + OR(C, B) ; \ + AND(C, A) ; \ + XOR(T, D) ; \ + XOR(C, T) ; \ + OR(T, A) ; \ + XOR(T, B) ; \ + AND(B, C) ; \ + XOR(B, D) ; \ + XOR(T, C) ; \ + AND(D, T) ; \ + XOR(T, B) ; \ + XOR(D, T) ; \ + NOT(T) ; \ + XOR(D, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, T) ; \ + ASSIGN(T, D) ; \ + ASSIGN(D, C) ; \ + ASSIGN(C, T) ; + +#define SBOX_D7(A, B, C, D, T) \ + XOR(A, C) ; \ + ASSIGN(T, C) ; \ + AND(C, A) ; \ + XOR(T, D) ; \ + NOT(C) ; \ + XOR(D, B) ; \ + XOR(C, D) ; \ + OR(T, A) ; \ + XOR(A, C) ; \ + XOR(D, T) ; \ + XOR(T, B) ; \ + AND(B, D) ; \ + XOR(B, A) ; \ + XOR(A, D) ; \ + OR(A, C) ; \ + XOR(D, B) ; \ + XOR(T, A) ; \ + ASSIGN(A, B) ; \ + ASSIGN(B, C) ; \ + ASSIGN(C, T) ; + +#define SBOX_D8(A, B, C, D, T) \ + ASSIGN(T, C) ; \ + XOR(C, A) ; \ + AND(A, D) ; \ + OR(T, D) ; \ + NOT(C) ; \ + XOR(D, B) ; \ + OR(B, A) ; \ + XOR(A, C) ; \ + AND(C, T) ; \ + AND(D, T) ; \ + XOR(B, C) ; \ + XOR(C, A) ; \ + OR(A, C) ; \ + XOR(T, B) ; \ + XOR(A, D) ; \ + XOR(D, T) ; \ + OR(T, A) ; \ + XOR(D, C) ; \ + XOR(T, C) ; \ + ASSIGN(C, B) ; \ + ASSIGN(B, A) ; \ + ASSIGN(A, D) ; \ + ASSIGN(D, T) ; + +#define TRANSFORM(A, B, C, D, T) \ + ROTL_IMM(A, 13) ; \ + ROTL_IMM(C, 3) ; \ + SHL2_3(T, A) ; \ + XOR(B, A) ; \ + XOR(D, C) ; \ + XOR(B, C) ; \ + XOR(D, T) ; \ + ROTL_IMM(B, 1) ; \ + ROTL_IMM(D, 7) ; \ + ASSIGN(T, B) ; \ + SHL_IMM(T, 7) ; \ + XOR(A, B) ; \ + XOR(C, D) ; \ + XOR(A, D) ; \ + XOR(C, T) ; \ + ROTL_IMM(A, 5) ; \ + ROTL_IMM(C, 22) ; + +#define I_TRANSFORM(A, B, C, D, T) \ + ROTR_IMM(C, 22) ; \ + ROTR_IMM(A, 5) ; \ + ASSIGN(T, B) ; \ + SHL_IMM(T, 7) ; \ + XOR(A, B) ; \ + XOR(C, D) ; \ + XOR(A, D) ; \ + XOR(C, T) ; \ + ROTR_IMM(D, 7) ; \ + ROTR_IMM(B, 1) ; \ + SHL2_3(T, A) ; \ + XOR(B, C) ; \ + XOR(D, C) ; \ + XOR(B, A) ; \ + XOR(D, T) ; \ + ROTR_IMM(C, 3) ; \ + ROTR_IMM(A, 13) ; + +#define KEY_XOR(A, B, C, D, N) \ + XOR(A, ARRAY4(EDI, (4*N ))) ; \ + XOR(B, ARRAY4(EDI, (4*N+1))) ; \ + XOR(C, ARRAY4(EDI, (4*N+2))) ; \ + XOR(D, ARRAY4(EDI, (4*N+3))) ; + +/* +* Serpent Encryption +*/ +START_FUNCTION(botan_serpent_x86_32_encrypt) + SPILL_REGS() +#define PUSHED 4 + + ASSIGN(EBP, ARG(1)) /* input block */ + ASSIGN(EAX, ARRAY4(EBP, 0)) + ASSIGN(EBX, ARRAY4(EBP, 1)) + ASSIGN(ECX, ARRAY4(EBP, 2)) + ASSIGN(EDX, ARRAY4(EBP, 3)) + + ASSIGN(EDI, ARG(3)) /* round keys */ + ZEROIZE(EBP) + +#define E_ROUND(A, B, C, D, T, N, SBOX) \ + KEY_XOR(A, B, C, D, N) \ + SBOX(A, B, C, D, T) \ + TRANSFORM(A, B, C, D, T) + + + E_ROUND(EAX, EBX, ECX, EDX, EBP, 0, SBOX_E1) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 1, SBOX_E2) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 2, SBOX_E3) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 3, SBOX_E4) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 4, SBOX_E5) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 5, SBOX_E6) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 6, SBOX_E7) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 7, SBOX_E8) + + E_ROUND(EAX, EBX, ECX, EDX, EBP, 8, SBOX_E1) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 9, SBOX_E2) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 10, SBOX_E3) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 11, SBOX_E4) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 12, SBOX_E5) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 13, SBOX_E6) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 14, SBOX_E7) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 15, SBOX_E8) + + E_ROUND(EAX, EBX, ECX, EDX, EBP, 16, SBOX_E1) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 17, SBOX_E2) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 18, SBOX_E3) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 19, SBOX_E4) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 20, SBOX_E5) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 21, SBOX_E6) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 22, SBOX_E7) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 23, SBOX_E8) + + E_ROUND(EAX, EBX, ECX, EDX, EBP, 24, SBOX_E1) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 25, SBOX_E2) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 26, SBOX_E3) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 27, SBOX_E4) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 28, SBOX_E5) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 29, SBOX_E6) + E_ROUND(EAX, EBX, ECX, EDX, EBP, 30, SBOX_E7) + + KEY_XOR(EAX, EBX, ECX, EDX, 31) + SBOX_E8(EAX, EBX, ECX, EDX, EBP) + KEY_XOR(EAX, EBX, ECX, EDX, 32) + + ASSIGN(EBP, ARG(2)) /* output block */ + ASSIGN(ARRAY4(EBP, 0), EAX) + ASSIGN(ARRAY4(EBP, 1), EBX) + ASSIGN(ARRAY4(EBP, 2), ECX) + ASSIGN(ARRAY4(EBP, 3), EDX) + + RESTORE_REGS() +#undef PUSHED +END_FUNCTION(botan_serpent_x86_32_encrypt) + +/* +* Serpent Decryption +*/ +START_FUNCTION(botan_serpent_x86_32_decrypt) + SPILL_REGS() +#define PUSHED 4 + + ASSIGN(EBP, ARG(1)) /* input block */ + ASSIGN(EAX, ARRAY4(EBP, 0)) + ASSIGN(EBX, ARRAY4(EBP, 1)) + ASSIGN(ECX, ARRAY4(EBP, 2)) + ASSIGN(EDX, ARRAY4(EBP, 3)) + + ASSIGN(EDI, ARG(3)) /* round keys */ + + ZEROIZE(EBP) + +#define D_ROUND(A, B, C, D, T, N, SBOX) \ + I_TRANSFORM(A, B, C, D, T) \ + SBOX(A, B, C, D, T) \ + KEY_XOR(A, B, C, D, N) \ + + KEY_XOR(EAX, EBX, ECX, EDX, 32) + SBOX_D8(EAX, EBX, ECX, EDX, EBP) + KEY_XOR(EAX, EBX, ECX, EDX, 31) + + D_ROUND(EAX, EBX, ECX, EDX, EBP, 30, SBOX_D7) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 29, SBOX_D6) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 28, SBOX_D5) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 27, SBOX_D4) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 26, SBOX_D3) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 25, SBOX_D2) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 24, SBOX_D1) + + D_ROUND(EAX, EBX, ECX, EDX, EBP, 23, SBOX_D8) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 22, SBOX_D7) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 21, SBOX_D6) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 20, SBOX_D5) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 19, SBOX_D4) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 18, SBOX_D3) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 17, SBOX_D2) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 16, SBOX_D1) + + D_ROUND(EAX, EBX, ECX, EDX, EBP, 15, SBOX_D8) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 14, SBOX_D7) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 13, SBOX_D6) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 12, SBOX_D5) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 11, SBOX_D4) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 10, SBOX_D3) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 9, SBOX_D2) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 8, SBOX_D1) + + D_ROUND(EAX, EBX, ECX, EDX, EBP, 7, SBOX_D8) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 6, SBOX_D7) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 5, SBOX_D6) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 4, SBOX_D5) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 3, SBOX_D4) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 2, SBOX_D3) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 1, SBOX_D2) + D_ROUND(EAX, EBX, ECX, EDX, EBP, 0, SBOX_D1) + + ASSIGN(EBP, ARG(2)) /* output block */ + ASSIGN(ARRAY4(EBP, 0), EAX) + ASSIGN(ARRAY4(EBP, 1), EBX) + ASSIGN(ARRAY4(EBP, 2), ECX) + ASSIGN(ARRAY4(EBP, 3), EDX) + + RESTORE_REGS() +#undef PUSHED +END_FUNCTION(botan_serpent_x86_32_decrypt) + +/* +* Serpent Key Schedule +*/ +START_FUNCTION(botan_serpent_x86_32_key_schedule) + SPILL_REGS() +#define PUSHED 4 + + ASSIGN(EDI, ARG(1)) /* round keys */ + ASSIGN(ESI, IMM(8)) + ADD_IMM(EDI, 32) + +START_LOOP(.L_SERP_EXPANSION) + ASSIGN(EAX, ARRAY4(EDI, -1)) + ASSIGN(EBX, ARRAY4(EDI, -3)) + ASSIGN(ECX, ARRAY4(EDI, -5)) + ASSIGN(EDX, ARRAY4(EDI, -8)) + + ASSIGN(EBP, ESI) + SUB_IMM(EBP, 8) + XOR(EBP, IMM(0x9E3779B9)) + XOR(EAX, EBX) + XOR(ECX, EDX) + XOR(EAX, EBP) + XOR(EAX, ECX) + + ROTL_IMM(EAX, 11) + + ASSIGN(ARRAY4(EDI, 0), EAX) + + ADD_IMM(ESI, 1) + ADD_IMM(EDI, 4) +LOOP_UNTIL_EQ(ESI, 140, .L_SERP_EXPANSION) + + ASSIGN(EDI, ARG(1)) /* round keys */ + +#define LOAD_AND_SBOX(MSG, SBOX) \ + ASSIGN(EAX, ARRAY4(EDI, (4*MSG+ 8))) ; \ + ASSIGN(EBX, ARRAY4(EDI, (4*MSG+ 9))) ; \ + ASSIGN(ECX, ARRAY4(EDI, (4*MSG+10))) ; \ + ASSIGN(EDX, ARRAY4(EDI, (4*MSG+11))) ; \ + SBOX(EAX, EBX, ECX, EDX, EBP) ; \ + ASSIGN(ARRAY4(EDI, (4*MSG+ 8)), EAX) ; \ + ASSIGN(ARRAY4(EDI, (4*MSG+ 9)), EBX) ; \ + ASSIGN(ARRAY4(EDI, (4*MSG+10)), ECX) ; \ + ASSIGN(ARRAY4(EDI, (4*MSG+11)), EDX) + + LOAD_AND_SBOX( 0, SBOX_E4) + LOAD_AND_SBOX( 1, SBOX_E3) + LOAD_AND_SBOX( 2, SBOX_E2) + LOAD_AND_SBOX( 3, SBOX_E1) + + LOAD_AND_SBOX( 4, SBOX_E8) + LOAD_AND_SBOX( 5, SBOX_E7) + LOAD_AND_SBOX( 6, SBOX_E6) + LOAD_AND_SBOX( 7, SBOX_E5) + LOAD_AND_SBOX( 8, SBOX_E4) + LOAD_AND_SBOX( 9, SBOX_E3) + LOAD_AND_SBOX(10, SBOX_E2) + LOAD_AND_SBOX(11, SBOX_E1) + + LOAD_AND_SBOX(12, SBOX_E8) + LOAD_AND_SBOX(13, SBOX_E7) + LOAD_AND_SBOX(14, SBOX_E6) + LOAD_AND_SBOX(15, SBOX_E5) + LOAD_AND_SBOX(16, SBOX_E4) + LOAD_AND_SBOX(17, SBOX_E3) + LOAD_AND_SBOX(18, SBOX_E2) + LOAD_AND_SBOX(19, SBOX_E1) + + LOAD_AND_SBOX(20, SBOX_E8) + LOAD_AND_SBOX(21, SBOX_E7) + LOAD_AND_SBOX(22, SBOX_E6) + LOAD_AND_SBOX(23, SBOX_E5) + LOAD_AND_SBOX(24, SBOX_E4) + LOAD_AND_SBOX(25, SBOX_E3) + LOAD_AND_SBOX(26, SBOX_E2) + LOAD_AND_SBOX(27, SBOX_E1) + + LOAD_AND_SBOX(28, SBOX_E8) + LOAD_AND_SBOX(29, SBOX_E7) + LOAD_AND_SBOX(30, SBOX_E6) + LOAD_AND_SBOX(31, SBOX_E5) + LOAD_AND_SBOX(32, SBOX_E4) + + RESTORE_REGS() +#undef PUSHED +END_FUNCTION(botan_serpent_x86_32_key_schedule) diff --git a/src/lib/block/skipjack/info.txt b/src/lib/block/skipjack/info.txt new file mode 100644 index 000000000..fb2bf70a5 --- /dev/null +++ b/src/lib/block/skipjack/info.txt @@ -0,0 +1 @@ +define SKIPJACK 20131128 diff --git a/src/lib/block/skipjack/skipjack.cpp b/src/lib/block/skipjack/skipjack.cpp new file mode 100644 index 000000000..be4024ad4 --- /dev/null +++ b/src/lib/block/skipjack/skipjack.cpp @@ -0,0 +1,200 @@ +/* +* Skipjack +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* Skipjack Stepping Rule 'A' +*/ +void step_A(u16bit& W1, u16bit& W4, size_t round, const byte FTAB[]) + { + byte G1 = get_byte(0, W1), G2 = get_byte(1, W1), G3; + + G3 = FTAB[((4*round-4)%10)*256 + G2] ^ G1; + G1 = FTAB[((4*round-3)%10)*256 + G3] ^ G2; + G2 = FTAB[((4*round-2)%10)*256 + G1] ^ G3; + G3 = FTAB[((4*round-1)%10)*256 + G2] ^ G1; + + W1 = make_u16bit(G2, G3); + W4 ^= W1 ^ round; + } + +/* +* Skipjack Stepping Rule 'B' +*/ +void step_B(u16bit& W1, u16bit& W2, size_t round, const byte FTAB[]) + { + W2 ^= W1 ^ round; + byte G1 = get_byte(0, W1), G2 = get_byte(1, W1), G3; + G3 = FTAB[((4*round-4)%10)*256 + G2] ^ G1; + G1 = FTAB[((4*round-3)%10)*256 + G3] ^ G2; + G2 = FTAB[((4*round-2)%10)*256 + G1] ^ G3; + G3 = FTAB[((4*round-1)%10)*256 + G2] ^ G1; + W1 = make_u16bit(G2, G3); + } + +/* +* Skipjack Invserse Stepping Rule 'A' +*/ +void step_Ai(u16bit& W1, u16bit& W2, size_t round, const byte FTAB[]) + { + W1 ^= W2 ^ round; + byte G1 = get_byte(1, W2), G2 = get_byte(0, W2), G3; + G3 = FTAB[((4 * round - 1) % 10)*256 + G2] ^ G1; + G1 = FTAB[((4 * round - 2) % 10)*256 + G3] ^ G2; + G2 = FTAB[((4 * round - 3) % 10)*256 + G1] ^ G3; + G3 = FTAB[((4 * round - 4) % 10)*256 + G2] ^ G1; + W2 = make_u16bit(G3, G2); + } + +/* +* Skipjack Invserse Stepping Rule 'B' +*/ +void step_Bi(u16bit& W2, u16bit& W3, size_t round, const byte FTAB[]) + { + byte G1 = get_byte(1, W2), G2 = get_byte(0, W2), G3; + G3 = FTAB[((4 * round - 1) % 10)*256 + G2] ^ G1; + G1 = FTAB[((4 * round - 2) % 10)*256 + G3] ^ G2; + G2 = FTAB[((4 * round - 3) % 10)*256 + G1] ^ G3; + G3 = FTAB[((4 * round - 4) % 10)*256 + G2] ^ G1; + W2 = make_u16bit(G3, G2); + W3 ^= W2 ^ round; + } + +} + +/* +* Skipjack Encryption +*/ +void Skipjack::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const byte* ftab = &FTAB[0]; + + for(size_t i = 0; i != blocks; ++i) + { + u16bit W1 = load_le(in, 3); + u16bit W2 = load_le(in, 2); + u16bit W3 = load_le(in, 1); + u16bit W4 = load_le(in, 0); + + step_A(W1, W4, 1, ftab); step_A(W4, W3, 2, ftab); + step_A(W3, W2, 3, ftab); step_A(W2, W1, 4, ftab); + step_A(W1, W4, 5, ftab); step_A(W4, W3, 6, ftab); + step_A(W3, W2, 7, ftab); step_A(W2, W1, 8, ftab); + + step_B(W1, W2, 9, ftab); step_B(W4, W1, 10, ftab); + step_B(W3, W4, 11, ftab); step_B(W2, W3, 12, ftab); + step_B(W1, W2, 13, ftab); step_B(W4, W1, 14, ftab); + step_B(W3, W4, 15, ftab); step_B(W2, W3, 16, ftab); + + step_A(W1, W4, 17, ftab); step_A(W4, W3, 18, ftab); + step_A(W3, W2, 19, ftab); step_A(W2, W1, 20, ftab); + step_A(W1, W4, 21, ftab); step_A(W4, W3, 22, ftab); + step_A(W3, W2, 23, ftab); step_A(W2, W1, 24, ftab); + + step_B(W1, W2, 25, ftab); step_B(W4, W1, 26, ftab); + step_B(W3, W4, 27, ftab); step_B(W2, W3, 28, ftab); + step_B(W1, W2, 29, ftab); step_B(W4, W1, 30, ftab); + step_B(W3, W4, 31, ftab); step_B(W2, W3, 32, ftab); + + store_le(out, W4, W3, W2, W1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Skipjack Decryption +*/ +void Skipjack::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const byte* ftab = &FTAB[0]; + + for(size_t i = 0; i != blocks; ++i) + { + u16bit W1 = load_le(in, 3); + u16bit W2 = load_le(in, 2); + u16bit W3 = load_le(in, 1); + u16bit W4 = load_le(in, 0); + + step_Bi(W2, W3, 32, ftab); step_Bi(W3, W4, 31, ftab); + step_Bi(W4, W1, 30, ftab); step_Bi(W1, W2, 29, ftab); + step_Bi(W2, W3, 28, ftab); step_Bi(W3, W4, 27, ftab); + step_Bi(W4, W1, 26, ftab); step_Bi(W1, W2, 25, ftab); + + step_Ai(W1, W2, 24, ftab); step_Ai(W2, W3, 23, ftab); + step_Ai(W3, W4, 22, ftab); step_Ai(W4, W1, 21, ftab); + step_Ai(W1, W2, 20, ftab); step_Ai(W2, W3, 19, ftab); + step_Ai(W3, W4, 18, ftab); step_Ai(W4, W1, 17, ftab); + + step_Bi(W2, W3, 16, ftab); step_Bi(W3, W4, 15, ftab); + step_Bi(W4, W1, 14, ftab); step_Bi(W1, W2, 13, ftab); + step_Bi(W2, W3, 12, ftab); step_Bi(W3, W4, 11, ftab); + step_Bi(W4, W1, 10, ftab); step_Bi(W1, W2, 9, ftab); + + step_Ai(W1, W2, 8, ftab); step_Ai(W2, W3, 7, ftab); + step_Ai(W3, W4, 6, ftab); step_Ai(W4, W1, 5, ftab); + step_Ai(W1, W2, 4, ftab); step_Ai(W2, W3, 3, ftab); + step_Ai(W3, W4, 2, ftab); step_Ai(W4, W1, 1, ftab); + + store_le(out, W4, W3, W2, W1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Skipjack Key Schedule +*/ +void Skipjack::key_schedule(const byte key[], size_t) + { + static const byte F[256] = { + 0xA3, 0xD7, 0x09, 0x83, 0xF8, 0x48, 0xF6, 0xF4, 0xB3, 0x21, 0x15, 0x78, + 0x99, 0xB1, 0xAF, 0xF9, 0xE7, 0x2D, 0x4D, 0x8A, 0xCE, 0x4C, 0xCA, 0x2E, + 0x52, 0x95, 0xD9, 0x1E, 0x4E, 0x38, 0x44, 0x28, 0x0A, 0xDF, 0x02, 0xA0, + 0x17, 0xF1, 0x60, 0x68, 0x12, 0xB7, 0x7A, 0xC3, 0xE9, 0xFA, 0x3D, 0x53, + 0x96, 0x84, 0x6B, 0xBA, 0xF2, 0x63, 0x9A, 0x19, 0x7C, 0xAE, 0xE5, 0xF5, + 0xF7, 0x16, 0x6A, 0xA2, 0x39, 0xB6, 0x7B, 0x0F, 0xC1, 0x93, 0x81, 0x1B, + 0xEE, 0xB4, 0x1A, 0xEA, 0xD0, 0x91, 0x2F, 0xB8, 0x55, 0xB9, 0xDA, 0x85, + 0x3F, 0x41, 0xBF, 0xE0, 0x5A, 0x58, 0x80, 0x5F, 0x66, 0x0B, 0xD8, 0x90, + 0x35, 0xD5, 0xC0, 0xA7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, + 0x6D, 0x98, 0x9B, 0x76, 0x97, 0xFC, 0xB2, 0xC2, 0xB0, 0xFE, 0xDB, 0x20, + 0xE1, 0xEB, 0xD6, 0xE4, 0xDD, 0x47, 0x4A, 0x1D, 0x42, 0xED, 0x9E, 0x6E, + 0x49, 0x3C, 0xCD, 0x43, 0x27, 0xD2, 0x07, 0xD4, 0xDE, 0xC7, 0x67, 0x18, + 0x89, 0xCB, 0x30, 0x1F, 0x8D, 0xC6, 0x8F, 0xAA, 0xC8, 0x74, 0xDC, 0xC9, + 0x5D, 0x5C, 0x31, 0xA4, 0x70, 0x88, 0x61, 0x2C, 0x9F, 0x0D, 0x2B, 0x87, + 0x50, 0x82, 0x54, 0x64, 0x26, 0x7D, 0x03, 0x40, 0x34, 0x4B, 0x1C, 0x73, + 0xD1, 0xC4, 0xFD, 0x3B, 0xCC, 0xFB, 0x7F, 0xAB, 0xE6, 0x3E, 0x5B, 0xA5, + 0xAD, 0x04, 0x23, 0x9C, 0x14, 0x51, 0x22, 0xF0, 0x29, 0x79, 0x71, 0x7E, + 0xFF, 0x8C, 0x0E, 0xE2, 0x0C, 0xEF, 0xBC, 0x72, 0x75, 0x6F, 0x37, 0xA1, + 0xEC, 0xD3, 0x8E, 0x62, 0x8B, 0x86, 0x10, 0xE8, 0x08, 0x77, 0x11, 0xBE, + 0x92, 0x4F, 0x24, 0xC5, 0x32, 0x36, 0x9D, 0xCF, 0xF3, 0xA6, 0xBB, 0xAC, + 0x5E, 0x6C, 0xA9, 0x13, 0x57, 0x25, 0xB5, 0xE3, 0xBD, 0xA8, 0x3A, 0x01, + 0x05, 0x59, 0x2A, 0x46 }; + + FTAB.resize(256*10); + for(size_t i = 0; i != 10; ++i) + for(size_t j = 0; j != 256; ++j) + FTAB[256*i+j] = F[j ^ key[9-i]]; + } + +/* +* Clear memory of sensitive data +*/ +void Skipjack::clear() + { + zap(FTAB); + } + +} diff --git a/src/lib/block/skipjack/skipjack.h b/src/lib/block/skipjack/skipjack.h new file mode 100644 index 000000000..60a55c8a5 --- /dev/null +++ b/src/lib/block/skipjack/skipjack.h @@ -0,0 +1,35 @@ +/* +* Skipjack +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SKIPJACK_H__ +#define BOTAN_SKIPJACK_H__ + +#include + +namespace Botan { + +/** +* Skipjack, a NSA designed cipher used in Fortezza +*/ +class BOTAN_DLL Skipjack : public Block_Cipher_Fixed_Params<8, 10> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Skipjack"; } + BlockCipher* clone() const { return new Skipjack; } + private: + void key_schedule(const byte[], size_t); + + secure_vector FTAB; + }; + +} + +#endif diff --git a/src/lib/block/square/info.txt b/src/lib/block/square/info.txt new file mode 100644 index 000000000..1335b35b2 --- /dev/null +++ b/src/lib/block/square/info.txt @@ -0,0 +1 @@ +define SQUARE 20131128 diff --git a/src/lib/block/square/sqr_tab.cpp b/src/lib/block/square/sqr_tab.cpp new file mode 100644 index 000000000..331bf3ea1 --- /dev/null +++ b/src/lib/block/square/sqr_tab.cpp @@ -0,0 +1,460 @@ +/* +* S-Box and Diffusion Tables for Square +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const byte Square::SE[256] = { +0xB1, 0xCE, 0xC3, 0x95, 0x5A, 0xAD, 0xE7, 0x02, 0x4D, 0x44, 0xFB, 0x91, 0x0C, +0x87, 0xA1, 0x50, 0xCB, 0x67, 0x54, 0xDD, 0x46, 0x8F, 0xE1, 0x4E, 0xF0, 0xFD, +0xFC, 0xEB, 0xF9, 0xC4, 0x1A, 0x6E, 0x5E, 0xF5, 0xCC, 0x8D, 0x1C, 0x56, 0x43, +0xFE, 0x07, 0x61, 0xF8, 0x75, 0x59, 0xFF, 0x03, 0x22, 0x8A, 0xD1, 0x13, 0xEE, +0x88, 0x00, 0x0E, 0x34, 0x15, 0x80, 0x94, 0xE3, 0xED, 0xB5, 0x53, 0x23, 0x4B, +0x47, 0x17, 0xA7, 0x90, 0x35, 0xAB, 0xD8, 0xB8, 0xDF, 0x4F, 0x57, 0x9A, 0x92, +0xDB, 0x1B, 0x3C, 0xC8, 0x99, 0x04, 0x8E, 0xE0, 0xD7, 0x7D, 0x85, 0xBB, 0x40, +0x2C, 0x3A, 0x45, 0xF1, 0x42, 0x65, 0x20, 0x41, 0x18, 0x72, 0x25, 0x93, 0x70, +0x36, 0x05, 0xF2, 0x0B, 0xA3, 0x79, 0xEC, 0x08, 0x27, 0x31, 0x32, 0xB6, 0x7C, +0xB0, 0x0A, 0x73, 0x5B, 0x7B, 0xB7, 0x81, 0xD2, 0x0D, 0x6A, 0x26, 0x9E, 0x58, +0x9C, 0x83, 0x74, 0xB3, 0xAC, 0x30, 0x7A, 0x69, 0x77, 0x0F, 0xAE, 0x21, 0xDE, +0xD0, 0x2E, 0x97, 0x10, 0xA4, 0x98, 0xA8, 0xD4, 0x68, 0x2D, 0x62, 0x29, 0x6D, +0x16, 0x49, 0x76, 0xC7, 0xE8, 0xC1, 0x96, 0x37, 0xE5, 0xCA, 0xF4, 0xE9, 0x63, +0x12, 0xC2, 0xA6, 0x14, 0xBC, 0xD3, 0x28, 0xAF, 0x2F, 0xE6, 0x24, 0x52, 0xC6, +0xA0, 0x09, 0xBD, 0x8C, 0xCF, 0x5D, 0x11, 0x5F, 0x01, 0xC5, 0x9F, 0x3D, 0xA2, +0x9B, 0xC9, 0x3B, 0xBE, 0x51, 0x19, 0x1F, 0x3F, 0x5C, 0xB2, 0xEF, 0x4A, 0xCD, +0xBF, 0xBA, 0x6F, 0x64, 0xD9, 0xF3, 0x3E, 0xB4, 0xAA, 0xDC, 0xD5, 0x06, 0xC0, +0x7E, 0xF6, 0x66, 0x6C, 0x84, 0x71, 0x38, 0xB9, 0x1D, 0x7F, 0x9D, 0x48, 0x8B, +0x2A, 0xDA, 0xA5, 0x33, 0x82, 0x39, 0xD6, 0x78, 0x86, 0xFA, 0xE4, 0x2B, 0xA9, +0x1E, 0x89, 0x60, 0x6B, 0xEA, 0x55, 0x4C, 0xF7, 0xE2 }; + +const byte Square::SD[256] = { +0x35, 0xBE, 0x07, 0x2E, 0x53, 0x69, 0xDB, 0x28, 0x6F, 0xB7, 0x76, 0x6B, 0x0C, +0x7D, 0x36, 0x8B, 0x92, 0xBC, 0xA9, 0x32, 0xAC, 0x38, 0x9C, 0x42, 0x63, 0xC8, +0x1E, 0x4F, 0x24, 0xE5, 0xF7, 0xC9, 0x61, 0x8D, 0x2F, 0x3F, 0xB3, 0x65, 0x7F, +0x70, 0xAF, 0x9A, 0xEA, 0xF5, 0x5B, 0x98, 0x90, 0xB1, 0x87, 0x71, 0x72, 0xED, +0x37, 0x45, 0x68, 0xA3, 0xE3, 0xEF, 0x5C, 0xC5, 0x50, 0xC1, 0xD6, 0xCA, 0x5A, +0x62, 0x5F, 0x26, 0x09, 0x5D, 0x14, 0x41, 0xE8, 0x9D, 0xCE, 0x40, 0xFD, 0x08, +0x17, 0x4A, 0x0F, 0xC7, 0xB4, 0x3E, 0x12, 0xFC, 0x25, 0x4B, 0x81, 0x2C, 0x04, +0x78, 0xCB, 0xBB, 0x20, 0xBD, 0xF9, 0x29, 0x99, 0xA8, 0xD3, 0x60, 0xDF, 0x11, +0x97, 0x89, 0x7E, 0xFA, 0xE0, 0x9B, 0x1F, 0xD2, 0x67, 0xE2, 0x64, 0x77, 0x84, +0x2B, 0x9E, 0x8A, 0xF1, 0x6D, 0x88, 0x79, 0x74, 0x57, 0xDD, 0xE6, 0x39, 0x7B, +0xEE, 0x83, 0xE1, 0x58, 0xF2, 0x0D, 0x34, 0xF8, 0x30, 0xE9, 0xB9, 0x23, 0x54, +0x15, 0x44, 0x0B, 0x4D, 0x66, 0x3A, 0x03, 0xA2, 0x91, 0x94, 0x52, 0x4C, 0xC3, +0x82, 0xE7, 0x80, 0xC0, 0xB6, 0x0E, 0xC2, 0x6C, 0x93, 0xEC, 0xAB, 0x43, 0x95, +0xF6, 0xD8, 0x46, 0x86, 0x05, 0x8C, 0xB0, 0x75, 0x00, 0xCC, 0x85, 0xD7, 0x3D, +0x73, 0x7A, 0x48, 0xE4, 0xD1, 0x59, 0xAD, 0xB8, 0xC6, 0xD0, 0xDC, 0xA1, 0xAA, +0x02, 0x1D, 0xBF, 0xB5, 0x9F, 0x51, 0xC4, 0xA5, 0x10, 0x22, 0xCF, 0x01, 0xBA, +0x8F, 0x31, 0x7C, 0xAE, 0x96, 0xDA, 0xF0, 0x56, 0x47, 0xD4, 0xEB, 0x4E, 0xD9, +0x13, 0x8E, 0x49, 0x55, 0x16, 0xFF, 0x3B, 0xF4, 0xA4, 0xB2, 0x06, 0xA0, 0xA7, +0xFB, 0x1B, 0x6E, 0x3C, 0x33, 0xCD, 0x18, 0x5E, 0x6A, 0xD5, 0xA6, 0x21, 0xDE, +0xFE, 0x2A, 0x1C, 0xF3, 0x0A, 0x1A, 0x19, 0x27, 0x2D }; + +const byte Square::Log[256] = { +0x00, 0x00, 0x01, 0x86, 0x02, 0x0D, 0x87, 0x4C, 0x03, 0xD2, 0x0E, 0xAE, 0x88, +0x22, 0x4D, 0x93, 0x04, 0x1A, 0xD3, 0xCB, 0x0F, 0x98, 0xAF, 0xA8, 0x89, 0xF0, +0x23, 0x59, 0x4E, 0x35, 0x94, 0x09, 0x05, 0x8F, 0x1B, 0x6E, 0xD4, 0x39, 0xCC, +0xBB, 0x10, 0x68, 0x99, 0x77, 0xB0, 0xDF, 0xA9, 0x72, 0x8A, 0xFA, 0xF1, 0xA0, +0x24, 0x52, 0x5A, 0x60, 0x4F, 0x2F, 0x36, 0xDC, 0x95, 0x32, 0x0A, 0x1F, 0x06, +0xA5, 0x90, 0x49, 0x1C, 0x5D, 0x6F, 0xB8, 0xD5, 0xC1, 0x3A, 0xB5, 0xCD, 0x63, +0xBC, 0x3D, 0x11, 0x44, 0x69, 0x81, 0x9A, 0x27, 0x78, 0xC4, 0xB1, 0xE6, 0xE0, +0xEA, 0xAA, 0x55, 0x73, 0xD8, 0x8B, 0xF6, 0xFB, 0x16, 0xF2, 0xF4, 0xA1, 0x40, +0x25, 0x42, 0x53, 0xE4, 0x5B, 0xA3, 0x61, 0xBF, 0x50, 0xF8, 0x30, 0x2D, 0x37, +0x8D, 0xDD, 0x66, 0x96, 0x18, 0x33, 0xEE, 0x0B, 0xFD, 0x20, 0xD0, 0x07, 0x57, +0xA6, 0xC9, 0x91, 0xAC, 0x4A, 0x84, 0x1D, 0xDA, 0x5E, 0x9E, 0x70, 0x75, 0xB9, +0x6C, 0xD6, 0xE8, 0xC2, 0x7F, 0x3B, 0xB3, 0xB6, 0x47, 0xCE, 0xEC, 0x64, 0x2B, +0xBD, 0xE2, 0x3E, 0x14, 0x12, 0x29, 0x45, 0x7D, 0x6A, 0x9C, 0x82, 0xC7, 0x9B, +0xC6, 0x28, 0x7C, 0x79, 0x7A, 0xC5, 0x7B, 0xB2, 0x46, 0xE7, 0x7E, 0xE1, 0x13, +0xEB, 0x2A, 0xAB, 0x83, 0x56, 0xC8, 0x74, 0x6B, 0xD9, 0x9D, 0x8C, 0x65, 0xF7, +0x2C, 0xFC, 0xCF, 0x17, 0xED, 0xF3, 0x3F, 0xF5, 0x15, 0xA2, 0xBE, 0x41, 0xE3, +0x26, 0xC3, 0x43, 0x80, 0x54, 0xD7, 0xE5, 0xE9, 0x5C, 0xB7, 0xA4, 0x48, 0x62, +0x3C, 0xC0, 0xB4, 0x51, 0x5F, 0xF9, 0x9F, 0x31, 0x1E, 0x2E, 0xDB, 0x38, 0xBA, +0x8E, 0x6D, 0xDE, 0x71, 0x67, 0x76, 0x97, 0xA7, 0x19, 0xCA, 0x34, 0x08, 0xEF, +0x58, 0x0C, 0x4B, 0xFE, 0x85, 0x21, 0x92, 0xD1, 0xAD }; + +const byte Square::ALog[255] = { +0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF5, 0x1F, 0x3E, 0x7C, 0xF8, +0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0xB5, 0x9F, 0xCB, 0x63, 0xC6, 0x79, 0xF2, +0x11, 0x22, 0x44, 0x88, 0xE5, 0x3F, 0x7E, 0xFC, 0x0D, 0x1A, 0x34, 0x68, 0xD0, +0x55, 0xAA, 0xA1, 0xB7, 0x9B, 0xC3, 0x73, 0xE6, 0x39, 0x72, 0xE4, 0x3D, 0x7A, +0xF4, 0x1D, 0x3A, 0x74, 0xE8, 0x25, 0x4A, 0x94, 0xDD, 0x4F, 0x9E, 0xC9, 0x67, +0xCE, 0x69, 0xD2, 0x51, 0xA2, 0xB1, 0x97, 0xDB, 0x43, 0x86, 0xF9, 0x07, 0x0E, +0x1C, 0x38, 0x70, 0xE0, 0x35, 0x6A, 0xD4, 0x5D, 0xBA, 0x81, 0xF7, 0x1B, 0x36, +0x6C, 0xD8, 0x45, 0x8A, 0xE1, 0x37, 0x6E, 0xDC, 0x4D, 0x9A, 0xC1, 0x77, 0xEE, +0x29, 0x52, 0xA4, 0xBD, 0x8F, 0xEB, 0x23, 0x46, 0x8C, 0xED, 0x2F, 0x5E, 0xBC, +0x8D, 0xEF, 0x2B, 0x56, 0xAC, 0xAD, 0xAF, 0xAB, 0xA3, 0xB3, 0x93, 0xD3, 0x53, +0xA6, 0xB9, 0x87, 0xFB, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x75, 0xEA, +0x21, 0x42, 0x84, 0xFD, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0x15, 0x2A, 0x54, 0xA8, +0xA5, 0xBF, 0x8B, 0xE3, 0x33, 0x66, 0xCC, 0x6D, 0xDA, 0x41, 0x82, 0xF1, 0x17, +0x2E, 0x5C, 0xB8, 0x85, 0xFF, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x95, 0xDF, 0x4B, +0x96, 0xD9, 0x47, 0x8E, 0xE9, 0x27, 0x4E, 0x9C, 0xCD, 0x6F, 0xDE, 0x49, 0x92, +0xD1, 0x57, 0xAE, 0xA9, 0xA7, 0xBB, 0x83, 0xF3, 0x13, 0x26, 0x4C, 0x98, 0xC5, +0x7F, 0xFE, 0x09, 0x12, 0x24, 0x48, 0x90, 0xD5, 0x5F, 0xBE, 0x89, 0xE7, 0x3B, +0x76, 0xEC, 0x2D, 0x5A, 0xB4, 0x9D, 0xCF, 0x6B, 0xD6, 0x59, 0xB2, 0x91, 0xD7, +0x5B, 0xB6, 0x99, 0xC7, 0x7B, 0xF6, 0x19, 0x32, 0x64, 0xC8, 0x65, 0xCA, 0x61, +0xC2, 0x71, 0xE2, 0x31, 0x62, 0xC4, 0x7D, 0xFA }; + +const u32bit Square::TE0[256] = { +0x97B1B126, 0x69CECEA7, 0x73C3C3B0, 0xDF95954A, 0xB45A5AEE, 0xAFADAD02, +0x3BE7E7DC, 0x04020206, 0x9A4D4DD7, 0x884444CC, 0x03FBFBF8, 0xD7919146, +0x180C0C14, 0xFB87877C, 0xB7A1A116, 0xA05050F0, 0x63CBCBA8, 0xCE6767A9, +0xA85454FC, 0x4FDDDD92, 0x8C4646CA, 0xEB8F8F64, 0x37E1E1D6, 0x9C4E4ED2, +0x15F0F0E5, 0x0FFDFDF2, 0x0DFCFCF1, 0x23EBEBC8, 0x07F9F9FE, 0x7DC4C4B9, +0x341A1A2E, 0xDC6E6EB2, 0xBC5E5EE2, 0x1FF5F5EA, 0x6DCCCCA1, 0xEF8D8D62, +0x381C1C24, 0xAC5656FA, 0x864343C5, 0x09FEFEF7, 0x0E070709, 0xC26161A3, +0x05F8F8FD, 0xEA75759F, 0xB25959EB, 0x0BFFFFF4, 0x06030305, 0x44222266, +0xE18A8A6B, 0x57D1D186, 0x26131335, 0x29EEEEC7, 0xE588886D, 0x00000000, +0x1C0E0E12, 0x6834345C, 0x2A15153F, 0xF5808075, 0xDD949449, 0x33E3E3D0, +0x2FEDEDC2, 0x9FB5B52A, 0xA65353F5, 0x46232365, 0x964B4BDD, 0x8E4747C9, +0x2E171739, 0xBBA7A71C, 0xD5909045, 0x6A35355F, 0xA3ABAB08, 0x45D8D89D, +0x85B8B83D, 0x4BDFDF94, 0x9E4F4FD1, 0xAE5757F9, 0xC19A9A5B, 0xD1929243, +0x43DBDB98, 0x361B1B2D, 0x783C3C44, 0x65C8C8AD, 0xC799995E, 0x0804040C, +0xE98E8E67, 0x35E0E0D5, 0x5BD7D78C, 0xFA7D7D87, 0xFF85857A, 0x83BBBB38, +0x804040C0, 0x582C2C74, 0x743A3A4E, 0x8A4545CF, 0x17F1F1E6, 0x844242C6, +0xCA6565AF, 0x40202060, 0x824141C3, 0x30181828, 0xE4727296, 0x4A25256F, +0xD3939340, 0xE0707090, 0x6C36365A, 0x0A05050F, 0x11F2F2E3, 0x160B0B1D, +0xB3A3A310, 0xF279798B, 0x2DECECC1, 0x10080818, 0x4E272769, 0x62313153, +0x64323256, 0x99B6B62F, 0xF87C7C84, 0x95B0B025, 0x140A0A1E, 0xE6737395, +0xB65B5BED, 0xF67B7B8D, 0x9BB7B72C, 0xF7818176, 0x51D2D283, 0x1A0D0D17, +0xD46A6ABE, 0x4C26266A, 0xC99E9E57, 0xB05858E8, 0xCD9C9C51, 0xF3838370, +0xE874749C, 0x93B3B320, 0xADACAC01, 0x60303050, 0xF47A7A8E, 0xD26969BB, +0xEE777799, 0x1E0F0F11, 0xA9AEAE07, 0x42212163, 0x49DEDE97, 0x55D0D085, +0x5C2E2E72, 0xDB97974C, 0x20101030, 0xBDA4A419, 0xC598985D, 0xA5A8A80D, +0x5DD4D489, 0xD06868B8, 0x5A2D2D77, 0xC46262A6, 0x5229297B, 0xDA6D6DB7, +0x2C16163A, 0x924949DB, 0xEC76769A, 0x7BC7C7BC, 0x25E8E8CD, 0x77C1C1B6, +0xD996964F, 0x6E373759, 0x3FE5E5DA, 0x61CACAAB, 0x1DF4F4E9, 0x27E9E9CE, +0xC66363A5, 0x24121236, 0x71C2C2B3, 0xB9A6A61F, 0x2814143C, 0x8DBCBC31, +0x53D3D380, 0x50282878, 0xABAFAF04, 0x5E2F2F71, 0x39E6E6DF, 0x4824246C, +0xA45252F6, 0x79C6C6BF, 0xB5A0A015, 0x1209091B, 0x8FBDBD32, 0xED8C8C61, +0x6BCFCFA4, 0xBA5D5DE7, 0x22111133, 0xBE5F5FE1, 0x02010103, 0x7FC5C5BA, +0xCB9F9F54, 0x7A3D3D47, 0xB1A2A213, 0xC39B9B58, 0x67C9C9AE, 0x763B3B4D, +0x89BEBE37, 0xA25151F3, 0x3219192B, 0x3E1F1F21, 0x7E3F3F41, 0xB85C5CE4, +0x91B2B223, 0x2BEFEFC4, 0x944A4ADE, 0x6FCDCDA2, 0x8BBFBF34, 0x81BABA3B, +0xDE6F6FB1, 0xC86464AC, 0x47D9D99E, 0x13F3F3E0, 0x7C3E3E42, 0x9DB4B429, +0xA1AAAA0B, 0x4DDCDC91, 0x5FD5D58A, 0x0C06060A, 0x75C0C0B5, 0xFC7E7E82, +0x19F6F6EF, 0xCC6666AA, 0xD86C6CB4, 0xFD848479, 0xE2717193, 0x70383848, +0x87B9B93E, 0x3A1D1D27, 0xFE7F7F81, 0xCF9D9D52, 0x904848D8, 0xE38B8B68, +0x542A2A7E, 0x41DADA9B, 0xBFA5A51A, 0x66333355, 0xF1828273, 0x7239394B, +0x59D6D68F, 0xF0787888, 0xF986867F, 0x01FAFAFB, 0x3DE4E4D9, 0x562B2B7D, +0xA7A9A90E, 0x3C1E1E22, 0xE789896E, 0xC06060A0, 0xD66B6BBD, 0x21EAEACB, +0xAA5555FF, 0x984C4CD4, 0x1BF7F7EC, 0x31E2E2D3 }; + +const u32bit Square::TE1[256] = { +0x2697B1B1, 0xA769CECE, 0xB073C3C3, 0x4ADF9595, 0xEEB45A5A, 0x02AFADAD, +0xDC3BE7E7, 0x06040202, 0xD79A4D4D, 0xCC884444, 0xF803FBFB, 0x46D79191, +0x14180C0C, 0x7CFB8787, 0x16B7A1A1, 0xF0A05050, 0xA863CBCB, 0xA9CE6767, +0xFCA85454, 0x924FDDDD, 0xCA8C4646, 0x64EB8F8F, 0xD637E1E1, 0xD29C4E4E, +0xE515F0F0, 0xF20FFDFD, 0xF10DFCFC, 0xC823EBEB, 0xFE07F9F9, 0xB97DC4C4, +0x2E341A1A, 0xB2DC6E6E, 0xE2BC5E5E, 0xEA1FF5F5, 0xA16DCCCC, 0x62EF8D8D, +0x24381C1C, 0xFAAC5656, 0xC5864343, 0xF709FEFE, 0x090E0707, 0xA3C26161, +0xFD05F8F8, 0x9FEA7575, 0xEBB25959, 0xF40BFFFF, 0x05060303, 0x66442222, +0x6BE18A8A, 0x8657D1D1, 0x35261313, 0xC729EEEE, 0x6DE58888, 0x00000000, +0x121C0E0E, 0x5C683434, 0x3F2A1515, 0x75F58080, 0x49DD9494, 0xD033E3E3, +0xC22FEDED, 0x2A9FB5B5, 0xF5A65353, 0x65462323, 0xDD964B4B, 0xC98E4747, +0x392E1717, 0x1CBBA7A7, 0x45D59090, 0x5F6A3535, 0x08A3ABAB, 0x9D45D8D8, +0x3D85B8B8, 0x944BDFDF, 0xD19E4F4F, 0xF9AE5757, 0x5BC19A9A, 0x43D19292, +0x9843DBDB, 0x2D361B1B, 0x44783C3C, 0xAD65C8C8, 0x5EC79999, 0x0C080404, +0x67E98E8E, 0xD535E0E0, 0x8C5BD7D7, 0x87FA7D7D, 0x7AFF8585, 0x3883BBBB, +0xC0804040, 0x74582C2C, 0x4E743A3A, 0xCF8A4545, 0xE617F1F1, 0xC6844242, +0xAFCA6565, 0x60402020, 0xC3824141, 0x28301818, 0x96E47272, 0x6F4A2525, +0x40D39393, 0x90E07070, 0x5A6C3636, 0x0F0A0505, 0xE311F2F2, 0x1D160B0B, +0x10B3A3A3, 0x8BF27979, 0xC12DECEC, 0x18100808, 0x694E2727, 0x53623131, +0x56643232, 0x2F99B6B6, 0x84F87C7C, 0x2595B0B0, 0x1E140A0A, 0x95E67373, +0xEDB65B5B, 0x8DF67B7B, 0x2C9BB7B7, 0x76F78181, 0x8351D2D2, 0x171A0D0D, +0xBED46A6A, 0x6A4C2626, 0x57C99E9E, 0xE8B05858, 0x51CD9C9C, 0x70F38383, +0x9CE87474, 0x2093B3B3, 0x01ADACAC, 0x50603030, 0x8EF47A7A, 0xBBD26969, +0x99EE7777, 0x111E0F0F, 0x07A9AEAE, 0x63422121, 0x9749DEDE, 0x8555D0D0, +0x725C2E2E, 0x4CDB9797, 0x30201010, 0x19BDA4A4, 0x5DC59898, 0x0DA5A8A8, +0x895DD4D4, 0xB8D06868, 0x775A2D2D, 0xA6C46262, 0x7B522929, 0xB7DA6D6D, +0x3A2C1616, 0xDB924949, 0x9AEC7676, 0xBC7BC7C7, 0xCD25E8E8, 0xB677C1C1, +0x4FD99696, 0x596E3737, 0xDA3FE5E5, 0xAB61CACA, 0xE91DF4F4, 0xCE27E9E9, +0xA5C66363, 0x36241212, 0xB371C2C2, 0x1FB9A6A6, 0x3C281414, 0x318DBCBC, +0x8053D3D3, 0x78502828, 0x04ABAFAF, 0x715E2F2F, 0xDF39E6E6, 0x6C482424, +0xF6A45252, 0xBF79C6C6, 0x15B5A0A0, 0x1B120909, 0x328FBDBD, 0x61ED8C8C, +0xA46BCFCF, 0xE7BA5D5D, 0x33221111, 0xE1BE5F5F, 0x03020101, 0xBA7FC5C5, +0x54CB9F9F, 0x477A3D3D, 0x13B1A2A2, 0x58C39B9B, 0xAE67C9C9, 0x4D763B3B, +0x3789BEBE, 0xF3A25151, 0x2B321919, 0x213E1F1F, 0x417E3F3F, 0xE4B85C5C, +0x2391B2B2, 0xC42BEFEF, 0xDE944A4A, 0xA26FCDCD, 0x348BBFBF, 0x3B81BABA, +0xB1DE6F6F, 0xACC86464, 0x9E47D9D9, 0xE013F3F3, 0x427C3E3E, 0x299DB4B4, +0x0BA1AAAA, 0x914DDCDC, 0x8A5FD5D5, 0x0A0C0606, 0xB575C0C0, 0x82FC7E7E, +0xEF19F6F6, 0xAACC6666, 0xB4D86C6C, 0x79FD8484, 0x93E27171, 0x48703838, +0x3E87B9B9, 0x273A1D1D, 0x81FE7F7F, 0x52CF9D9D, 0xD8904848, 0x68E38B8B, +0x7E542A2A, 0x9B41DADA, 0x1ABFA5A5, 0x55663333, 0x73F18282, 0x4B723939, +0x8F59D6D6, 0x88F07878, 0x7FF98686, 0xFB01FAFA, 0xD93DE4E4, 0x7D562B2B, +0x0EA7A9A9, 0x223C1E1E, 0x6EE78989, 0xA0C06060, 0xBDD66B6B, 0xCB21EAEA, +0xFFAA5555, 0xD4984C4C, 0xEC1BF7F7, 0xD331E2E2 }; + +const u32bit Square::TE2[256] = { +0xB12697B1, 0xCEA769CE, 0xC3B073C3, 0x954ADF95, 0x5AEEB45A, 0xAD02AFAD, +0xE7DC3BE7, 0x02060402, 0x4DD79A4D, 0x44CC8844, 0xFBF803FB, 0x9146D791, +0x0C14180C, 0x877CFB87, 0xA116B7A1, 0x50F0A050, 0xCBA863CB, 0x67A9CE67, +0x54FCA854, 0xDD924FDD, 0x46CA8C46, 0x8F64EB8F, 0xE1D637E1, 0x4ED29C4E, +0xF0E515F0, 0xFDF20FFD, 0xFCF10DFC, 0xEBC823EB, 0xF9FE07F9, 0xC4B97DC4, +0x1A2E341A, 0x6EB2DC6E, 0x5EE2BC5E, 0xF5EA1FF5, 0xCCA16DCC, 0x8D62EF8D, +0x1C24381C, 0x56FAAC56, 0x43C58643, 0xFEF709FE, 0x07090E07, 0x61A3C261, +0xF8FD05F8, 0x759FEA75, 0x59EBB259, 0xFFF40BFF, 0x03050603, 0x22664422, +0x8A6BE18A, 0xD18657D1, 0x13352613, 0xEEC729EE, 0x886DE588, 0x00000000, +0x0E121C0E, 0x345C6834, 0x153F2A15, 0x8075F580, 0x9449DD94, 0xE3D033E3, +0xEDC22FED, 0xB52A9FB5, 0x53F5A653, 0x23654623, 0x4BDD964B, 0x47C98E47, +0x17392E17, 0xA71CBBA7, 0x9045D590, 0x355F6A35, 0xAB08A3AB, 0xD89D45D8, +0xB83D85B8, 0xDF944BDF, 0x4FD19E4F, 0x57F9AE57, 0x9A5BC19A, 0x9243D192, +0xDB9843DB, 0x1B2D361B, 0x3C44783C, 0xC8AD65C8, 0x995EC799, 0x040C0804, +0x8E67E98E, 0xE0D535E0, 0xD78C5BD7, 0x7D87FA7D, 0x857AFF85, 0xBB3883BB, +0x40C08040, 0x2C74582C, 0x3A4E743A, 0x45CF8A45, 0xF1E617F1, 0x42C68442, +0x65AFCA65, 0x20604020, 0x41C38241, 0x18283018, 0x7296E472, 0x256F4A25, +0x9340D393, 0x7090E070, 0x365A6C36, 0x050F0A05, 0xF2E311F2, 0x0B1D160B, +0xA310B3A3, 0x798BF279, 0xECC12DEC, 0x08181008, 0x27694E27, 0x31536231, +0x32566432, 0xB62F99B6, 0x7C84F87C, 0xB02595B0, 0x0A1E140A, 0x7395E673, +0x5BEDB65B, 0x7B8DF67B, 0xB72C9BB7, 0x8176F781, 0xD28351D2, 0x0D171A0D, +0x6ABED46A, 0x266A4C26, 0x9E57C99E, 0x58E8B058, 0x9C51CD9C, 0x8370F383, +0x749CE874, 0xB32093B3, 0xAC01ADAC, 0x30506030, 0x7A8EF47A, 0x69BBD269, +0x7799EE77, 0x0F111E0F, 0xAE07A9AE, 0x21634221, 0xDE9749DE, 0xD08555D0, +0x2E725C2E, 0x974CDB97, 0x10302010, 0xA419BDA4, 0x985DC598, 0xA80DA5A8, +0xD4895DD4, 0x68B8D068, 0x2D775A2D, 0x62A6C462, 0x297B5229, 0x6DB7DA6D, +0x163A2C16, 0x49DB9249, 0x769AEC76, 0xC7BC7BC7, 0xE8CD25E8, 0xC1B677C1, +0x964FD996, 0x37596E37, 0xE5DA3FE5, 0xCAAB61CA, 0xF4E91DF4, 0xE9CE27E9, +0x63A5C663, 0x12362412, 0xC2B371C2, 0xA61FB9A6, 0x143C2814, 0xBC318DBC, +0xD38053D3, 0x28785028, 0xAF04ABAF, 0x2F715E2F, 0xE6DF39E6, 0x246C4824, +0x52F6A452, 0xC6BF79C6, 0xA015B5A0, 0x091B1209, 0xBD328FBD, 0x8C61ED8C, +0xCFA46BCF, 0x5DE7BA5D, 0x11332211, 0x5FE1BE5F, 0x01030201, 0xC5BA7FC5, +0x9F54CB9F, 0x3D477A3D, 0xA213B1A2, 0x9B58C39B, 0xC9AE67C9, 0x3B4D763B, +0xBE3789BE, 0x51F3A251, 0x192B3219, 0x1F213E1F, 0x3F417E3F, 0x5CE4B85C, +0xB22391B2, 0xEFC42BEF, 0x4ADE944A, 0xCDA26FCD, 0xBF348BBF, 0xBA3B81BA, +0x6FB1DE6F, 0x64ACC864, 0xD99E47D9, 0xF3E013F3, 0x3E427C3E, 0xB4299DB4, +0xAA0BA1AA, 0xDC914DDC, 0xD58A5FD5, 0x060A0C06, 0xC0B575C0, 0x7E82FC7E, +0xF6EF19F6, 0x66AACC66, 0x6CB4D86C, 0x8479FD84, 0x7193E271, 0x38487038, +0xB93E87B9, 0x1D273A1D, 0x7F81FE7F, 0x9D52CF9D, 0x48D89048, 0x8B68E38B, +0x2A7E542A, 0xDA9B41DA, 0xA51ABFA5, 0x33556633, 0x8273F182, 0x394B7239, +0xD68F59D6, 0x7888F078, 0x867FF986, 0xFAFB01FA, 0xE4D93DE4, 0x2B7D562B, +0xA90EA7A9, 0x1E223C1E, 0x896EE789, 0x60A0C060, 0x6BBDD66B, 0xEACB21EA, +0x55FFAA55, 0x4CD4984C, 0xF7EC1BF7, 0xE2D331E2 }; + +const u32bit Square::TE3[256] = { +0xB1B12697, 0xCECEA769, 0xC3C3B073, 0x95954ADF, 0x5A5AEEB4, 0xADAD02AF, +0xE7E7DC3B, 0x02020604, 0x4D4DD79A, 0x4444CC88, 0xFBFBF803, 0x919146D7, +0x0C0C1418, 0x87877CFB, 0xA1A116B7, 0x5050F0A0, 0xCBCBA863, 0x6767A9CE, +0x5454FCA8, 0xDDDD924F, 0x4646CA8C, 0x8F8F64EB, 0xE1E1D637, 0x4E4ED29C, +0xF0F0E515, 0xFDFDF20F, 0xFCFCF10D, 0xEBEBC823, 0xF9F9FE07, 0xC4C4B97D, +0x1A1A2E34, 0x6E6EB2DC, 0x5E5EE2BC, 0xF5F5EA1F, 0xCCCCA16D, 0x8D8D62EF, +0x1C1C2438, 0x5656FAAC, 0x4343C586, 0xFEFEF709, 0x0707090E, 0x6161A3C2, +0xF8F8FD05, 0x75759FEA, 0x5959EBB2, 0xFFFFF40B, 0x03030506, 0x22226644, +0x8A8A6BE1, 0xD1D18657, 0x13133526, 0xEEEEC729, 0x88886DE5, 0x00000000, +0x0E0E121C, 0x34345C68, 0x15153F2A, 0x808075F5, 0x949449DD, 0xE3E3D033, +0xEDEDC22F, 0xB5B52A9F, 0x5353F5A6, 0x23236546, 0x4B4BDD96, 0x4747C98E, +0x1717392E, 0xA7A71CBB, 0x909045D5, 0x35355F6A, 0xABAB08A3, 0xD8D89D45, +0xB8B83D85, 0xDFDF944B, 0x4F4FD19E, 0x5757F9AE, 0x9A9A5BC1, 0x929243D1, +0xDBDB9843, 0x1B1B2D36, 0x3C3C4478, 0xC8C8AD65, 0x99995EC7, 0x04040C08, +0x8E8E67E9, 0xE0E0D535, 0xD7D78C5B, 0x7D7D87FA, 0x85857AFF, 0xBBBB3883, +0x4040C080, 0x2C2C7458, 0x3A3A4E74, 0x4545CF8A, 0xF1F1E617, 0x4242C684, +0x6565AFCA, 0x20206040, 0x4141C382, 0x18182830, 0x727296E4, 0x25256F4A, +0x939340D3, 0x707090E0, 0x36365A6C, 0x05050F0A, 0xF2F2E311, 0x0B0B1D16, +0xA3A310B3, 0x79798BF2, 0xECECC12D, 0x08081810, 0x2727694E, 0x31315362, +0x32325664, 0xB6B62F99, 0x7C7C84F8, 0xB0B02595, 0x0A0A1E14, 0x737395E6, +0x5B5BEDB6, 0x7B7B8DF6, 0xB7B72C9B, 0x818176F7, 0xD2D28351, 0x0D0D171A, +0x6A6ABED4, 0x26266A4C, 0x9E9E57C9, 0x5858E8B0, 0x9C9C51CD, 0x838370F3, +0x74749CE8, 0xB3B32093, 0xACAC01AD, 0x30305060, 0x7A7A8EF4, 0x6969BBD2, +0x777799EE, 0x0F0F111E, 0xAEAE07A9, 0x21216342, 0xDEDE9749, 0xD0D08555, +0x2E2E725C, 0x97974CDB, 0x10103020, 0xA4A419BD, 0x98985DC5, 0xA8A80DA5, +0xD4D4895D, 0x6868B8D0, 0x2D2D775A, 0x6262A6C4, 0x29297B52, 0x6D6DB7DA, +0x16163A2C, 0x4949DB92, 0x76769AEC, 0xC7C7BC7B, 0xE8E8CD25, 0xC1C1B677, +0x96964FD9, 0x3737596E, 0xE5E5DA3F, 0xCACAAB61, 0xF4F4E91D, 0xE9E9CE27, +0x6363A5C6, 0x12123624, 0xC2C2B371, 0xA6A61FB9, 0x14143C28, 0xBCBC318D, +0xD3D38053, 0x28287850, 0xAFAF04AB, 0x2F2F715E, 0xE6E6DF39, 0x24246C48, +0x5252F6A4, 0xC6C6BF79, 0xA0A015B5, 0x09091B12, 0xBDBD328F, 0x8C8C61ED, +0xCFCFA46B, 0x5D5DE7BA, 0x11113322, 0x5F5FE1BE, 0x01010302, 0xC5C5BA7F, +0x9F9F54CB, 0x3D3D477A, 0xA2A213B1, 0x9B9B58C3, 0xC9C9AE67, 0x3B3B4D76, +0xBEBE3789, 0x5151F3A2, 0x19192B32, 0x1F1F213E, 0x3F3F417E, 0x5C5CE4B8, +0xB2B22391, 0xEFEFC42B, 0x4A4ADE94, 0xCDCDA26F, 0xBFBF348B, 0xBABA3B81, +0x6F6FB1DE, 0x6464ACC8, 0xD9D99E47, 0xF3F3E013, 0x3E3E427C, 0xB4B4299D, +0xAAAA0BA1, 0xDCDC914D, 0xD5D58A5F, 0x06060A0C, 0xC0C0B575, 0x7E7E82FC, +0xF6F6EF19, 0x6666AACC, 0x6C6CB4D8, 0x848479FD, 0x717193E2, 0x38384870, +0xB9B93E87, 0x1D1D273A, 0x7F7F81FE, 0x9D9D52CF, 0x4848D890, 0x8B8B68E3, +0x2A2A7E54, 0xDADA9B41, 0xA5A51ABF, 0x33335566, 0x828273F1, 0x39394B72, +0xD6D68F59, 0x787888F0, 0x86867FF9, 0xFAFAFB01, 0xE4E4D93D, 0x2B2B7D56, +0xA9A90EA7, 0x1E1E223C, 0x89896EE7, 0x6060A0C0, 0x6B6BBDD6, 0xEAEACB21, +0x5555FFAA, 0x4C4CD498, 0xF7F7EC1B, 0xE2E2D331 }; + +const u32bit Square::TD0[256] = { +0xE368BC02, 0x5585620C, 0x2A3F2331, 0x61AB13F7, 0x98D46D72, 0x21CB9A19, +0x3C22A461, 0x459D3DCD, 0x05FDB423, 0x2BC4075F, 0x9B2C01C0, 0x3DD9800F, +0x486C5C74, 0xF97F7E85, 0xF173AB1F, 0xB6EDDE0E, 0x283C6BED, 0x4997781A, +0x9F2A918D, 0xC9579F33, 0xA907A8AA, 0xA50DED7D, 0x7C422D8F, 0x764DB0C9, +0x4D91E857, 0xCEA963CC, 0xB4EE96D2, 0x3028E1B6, 0x0DF161B9, 0xBD196726, +0x419BAD80, 0xC0A06EC7, 0x5183F241, 0x92DBF034, 0x6FA21EFC, 0x8F32CE4C, +0x13E03373, 0x69A7C66D, 0xE56D6493, 0xBF1A2FFA, 0xBB1CBFB7, 0x587403B5, +0xE76E2C4F, 0x5D89B796, 0xE89C052A, 0x446619A3, 0x342E71FB, 0x0FF22965, +0xFE81827A, 0xB11322F1, 0xA30835EC, 0xCD510F7E, 0xFF7AA614, 0x5C7293F8, +0x2FC29712, 0xF370E3C3, 0x992F491C, 0xD1431568, 0xC2A3261B, 0x88CC32B3, +0x8ACF7A6F, 0xB0E8069F, 0x7A47F51E, 0xD2BB79DA, 0xE6950821, 0x4398E55C, +0xD0B83106, 0x11E37BAF, 0x7E416553, 0xCCAA2B10, 0xD8B4E49C, 0x6456A7D4, +0xFB7C3659, 0x724B2084, 0xEA9F4DF6, 0x6A5FAADF, 0x2DC1DFCE, 0x70486858, +0xCAAFF381, 0x0605D891, 0x5A774B69, 0x94DE28A5, 0x39DF1042, 0x813BC347, +0xFC82CAA6, 0x23C8D2C5, 0x03F86CB2, 0x080CD59A, 0xDAB7AC40, 0x7DB909E1, +0x3824342C, 0xCF5247A2, 0xDCB274D1, 0x63A85B2B, 0x35D55595, 0x479E7511, +0x15E5EBE2, 0x4B9430C6, 0x4A6F14A8, 0x91239C86, 0x4C6ACC39, 0x5F8AFF4A, +0x0406904D, 0xEE99DDBB, 0x1E1152CA, 0xAAFFC418, 0xEB646998, 0x07FEFCFF, +0x8B345E01, 0x567D0EBE, 0xBAE79BD9, 0x4263C132, 0x75B5DC7B, 0x97264417, +0x67AECB66, 0x95250CCB, 0xEC9A9567, 0x57862AD0, 0x60503799, 0xB8E4D305, +0x65AD83BA, 0x19EFAE35, 0xA4F6C913, 0xC15B4AA9, 0x873E1BD6, 0xA0F0595E, +0x18148A5B, 0xAF02703B, 0xAB04E076, 0xDD4950BF, 0xDF4A1863, 0xC6A5B656, +0x853D530A, 0xFA871237, 0x77B694A7, 0x4665517F, 0xED61B109, 0x1BECE6E9, +0xD5458525, 0xF5753B52, 0x7FBA413D, 0x27CE4288, 0xB2EB4E43, 0xD6BDE997, +0x527B9EF3, 0x62537F45, 0x2C3AFBA0, 0x7BBCD170, 0xB91FF76B, 0x121B171D, +0xFD79EEC8, 0x3A277CF0, 0x0C0A45D7, 0x96DD6079, 0x2233F6AB, 0xACFA1C89, +0xC8ACBB5D, 0xA10B7D30, 0xD4BEA14B, 0xBEE10B94, 0x25CD0A54, 0x547E4662, +0xA2F31182, 0x17E6A33E, 0x263566E6, 0xC3580275, 0x83388B9B, 0x7844BDC2, +0x020348DC, 0x4F92A08B, 0x2E39B37C, 0x4E6984E5, 0xF0888F71, 0x362D3927, +0x9CD2FD3F, 0x01FB246E, 0x893716DD, 0x00000000, 0xF68D57E0, 0xE293986C, +0x744EF815, 0x9320D45A, 0xAD0138E7, 0xD3405DB4, 0x1A17C287, 0xB3106A2D, +0x5078D62F, 0xF48E1F3C, 0xA70EA5A1, 0x71B34C36, 0x9AD725AE, 0x5E71DB24, +0x161D8750, 0xEF62F9D5, 0x8D318690, 0x1C121A16, 0xA6F581CF, 0x5B8C6F07, +0x37D61D49, 0x6E593A92, 0x84C67764, 0x86C53FB8, 0xD746CDF9, 0xE090D0B0, +0x29C74F83, 0xE49640FD, 0x0E090D0B, 0x6DA15620, 0x8EC9EA22, 0xDB4C882E, +0xF776738E, 0xB515B2BC, 0x10185FC1, 0x322BA96A, 0x6BA48EB1, 0xAEF95455, +0x406089EE, 0x6655EF08, 0xE9672144, 0x3E21ECBD, 0x2030BE77, 0xF28BC7AD, +0x80C0E729, 0x141ECF8C, 0xBCE24348, 0xC4A6FE8A, 0x31D3C5D8, 0xB716FA60, +0x5380BA9D, 0xD94FC0F2, 0x1DE93E78, 0x24362E3A, 0xE16BF4DE, 0xCB54D7EF, +0x09F7F1F4, 0x82C3AFF5, 0x0BF4B928, 0x9D29D951, 0xC75E9238, 0xF8845AEB, +0x90D8B8E8, 0xDEB13C0D, 0x33D08D04, 0x685CE203, 0xC55DDAE4, 0x3BDC589E, +0x0A0F9D46, 0x3FDAC8D3, 0x598F27DB, 0xA8FC8CC4, 0x79BF99AC, 0x6C5A724E, +0x8CCAA2FE, 0x9ED1B5E3, 0x1FEA76A4, 0x73B004EA }; + +const u32bit Square::TD1[256] = { +0x02E368BC, 0x0C558562, 0x312A3F23, 0xF761AB13, 0x7298D46D, 0x1921CB9A, +0x613C22A4, 0xCD459D3D, 0x2305FDB4, 0x5F2BC407, 0xC09B2C01, 0x0F3DD980, +0x74486C5C, 0x85F97F7E, 0x1FF173AB, 0x0EB6EDDE, 0xED283C6B, 0x1A499778, +0x8D9F2A91, 0x33C9579F, 0xAAA907A8, 0x7DA50DED, 0x8F7C422D, 0xC9764DB0, +0x574D91E8, 0xCCCEA963, 0xD2B4EE96, 0xB63028E1, 0xB90DF161, 0x26BD1967, +0x80419BAD, 0xC7C0A06E, 0x415183F2, 0x3492DBF0, 0xFC6FA21E, 0x4C8F32CE, +0x7313E033, 0x6D69A7C6, 0x93E56D64, 0xFABF1A2F, 0xB7BB1CBF, 0xB5587403, +0x4FE76E2C, 0x965D89B7, 0x2AE89C05, 0xA3446619, 0xFB342E71, 0x650FF229, +0x7AFE8182, 0xF1B11322, 0xECA30835, 0x7ECD510F, 0x14FF7AA6, 0xF85C7293, +0x122FC297, 0xC3F370E3, 0x1C992F49, 0x68D14315, 0x1BC2A326, 0xB388CC32, +0x6F8ACF7A, 0x9FB0E806, 0x1E7A47F5, 0xDAD2BB79, 0x21E69508, 0x5C4398E5, +0x06D0B831, 0xAF11E37B, 0x537E4165, 0x10CCAA2B, 0x9CD8B4E4, 0xD46456A7, +0x59FB7C36, 0x84724B20, 0xF6EA9F4D, 0xDF6A5FAA, 0xCE2DC1DF, 0x58704868, +0x81CAAFF3, 0x910605D8, 0x695A774B, 0xA594DE28, 0x4239DF10, 0x47813BC3, +0xA6FC82CA, 0xC523C8D2, 0xB203F86C, 0x9A080CD5, 0x40DAB7AC, 0xE17DB909, +0x2C382434, 0xA2CF5247, 0xD1DCB274, 0x2B63A85B, 0x9535D555, 0x11479E75, +0xE215E5EB, 0xC64B9430, 0xA84A6F14, 0x8691239C, 0x394C6ACC, 0x4A5F8AFF, +0x4D040690, 0xBBEE99DD, 0xCA1E1152, 0x18AAFFC4, 0x98EB6469, 0xFF07FEFC, +0x018B345E, 0xBE567D0E, 0xD9BAE79B, 0x324263C1, 0x7B75B5DC, 0x17972644, +0x6667AECB, 0xCB95250C, 0x67EC9A95, 0xD057862A, 0x99605037, 0x05B8E4D3, +0xBA65AD83, 0x3519EFAE, 0x13A4F6C9, 0xA9C15B4A, 0xD6873E1B, 0x5EA0F059, +0x5B18148A, 0x3BAF0270, 0x76AB04E0, 0xBFDD4950, 0x63DF4A18, 0x56C6A5B6, +0x0A853D53, 0x37FA8712, 0xA777B694, 0x7F466551, 0x09ED61B1, 0xE91BECE6, +0x25D54585, 0x52F5753B, 0x3D7FBA41, 0x8827CE42, 0x43B2EB4E, 0x97D6BDE9, +0xF3527B9E, 0x4562537F, 0xA02C3AFB, 0x707BBCD1, 0x6BB91FF7, 0x1D121B17, +0xC8FD79EE, 0xF03A277C, 0xD70C0A45, 0x7996DD60, 0xAB2233F6, 0x89ACFA1C, +0x5DC8ACBB, 0x30A10B7D, 0x4BD4BEA1, 0x94BEE10B, 0x5425CD0A, 0x62547E46, +0x82A2F311, 0x3E17E6A3, 0xE6263566, 0x75C35802, 0x9B83388B, 0xC27844BD, +0xDC020348, 0x8B4F92A0, 0x7C2E39B3, 0xE54E6984, 0x71F0888F, 0x27362D39, +0x3F9CD2FD, 0x6E01FB24, 0xDD893716, 0x00000000, 0xE0F68D57, 0x6CE29398, +0x15744EF8, 0x5A9320D4, 0xE7AD0138, 0xB4D3405D, 0x871A17C2, 0x2DB3106A, +0x2F5078D6, 0x3CF48E1F, 0xA1A70EA5, 0x3671B34C, 0xAE9AD725, 0x245E71DB, +0x50161D87, 0xD5EF62F9, 0x908D3186, 0x161C121A, 0xCFA6F581, 0x075B8C6F, +0x4937D61D, 0x926E593A, 0x6484C677, 0xB886C53F, 0xF9D746CD, 0xB0E090D0, +0x8329C74F, 0xFDE49640, 0x0B0E090D, 0x206DA156, 0x228EC9EA, 0x2EDB4C88, +0x8EF77673, 0xBCB515B2, 0xC110185F, 0x6A322BA9, 0xB16BA48E, 0x55AEF954, +0xEE406089, 0x086655EF, 0x44E96721, 0xBD3E21EC, 0x772030BE, 0xADF28BC7, +0x2980C0E7, 0x8C141ECF, 0x48BCE243, 0x8AC4A6FE, 0xD831D3C5, 0x60B716FA, +0x9D5380BA, 0xF2D94FC0, 0x781DE93E, 0x3A24362E, 0xDEE16BF4, 0xEFCB54D7, +0xF409F7F1, 0xF582C3AF, 0x280BF4B9, 0x519D29D9, 0x38C75E92, 0xEBF8845A, +0xE890D8B8, 0x0DDEB13C, 0x0433D08D, 0x03685CE2, 0xE4C55DDA, 0x9E3BDC58, +0x460A0F9D, 0xD33FDAC8, 0xDB598F27, 0xC4A8FC8C, 0xAC79BF99, 0x4E6C5A72, +0xFE8CCAA2, 0xE39ED1B5, 0xA41FEA76, 0xEA73B004 }; + +const u32bit Square::TD2[256] = { +0xBC02E368, 0x620C5585, 0x23312A3F, 0x13F761AB, 0x6D7298D4, 0x9A1921CB, +0xA4613C22, 0x3DCD459D, 0xB42305FD, 0x075F2BC4, 0x01C09B2C, 0x800F3DD9, +0x5C74486C, 0x7E85F97F, 0xAB1FF173, 0xDE0EB6ED, 0x6BED283C, 0x781A4997, +0x918D9F2A, 0x9F33C957, 0xA8AAA907, 0xED7DA50D, 0x2D8F7C42, 0xB0C9764D, +0xE8574D91, 0x63CCCEA9, 0x96D2B4EE, 0xE1B63028, 0x61B90DF1, 0x6726BD19, +0xAD80419B, 0x6EC7C0A0, 0xF2415183, 0xF03492DB, 0x1EFC6FA2, 0xCE4C8F32, +0x337313E0, 0xC66D69A7, 0x6493E56D, 0x2FFABF1A, 0xBFB7BB1C, 0x03B55874, +0x2C4FE76E, 0xB7965D89, 0x052AE89C, 0x19A34466, 0x71FB342E, 0x29650FF2, +0x827AFE81, 0x22F1B113, 0x35ECA308, 0x0F7ECD51, 0xA614FF7A, 0x93F85C72, +0x97122FC2, 0xE3C3F370, 0x491C992F, 0x1568D143, 0x261BC2A3, 0x32B388CC, +0x7A6F8ACF, 0x069FB0E8, 0xF51E7A47, 0x79DAD2BB, 0x0821E695, 0xE55C4398, +0x3106D0B8, 0x7BAF11E3, 0x65537E41, 0x2B10CCAA, 0xE49CD8B4, 0xA7D46456, +0x3659FB7C, 0x2084724B, 0x4DF6EA9F, 0xAADF6A5F, 0xDFCE2DC1, 0x68587048, +0xF381CAAF, 0xD8910605, 0x4B695A77, 0x28A594DE, 0x104239DF, 0xC347813B, +0xCAA6FC82, 0xD2C523C8, 0x6CB203F8, 0xD59A080C, 0xAC40DAB7, 0x09E17DB9, +0x342C3824, 0x47A2CF52, 0x74D1DCB2, 0x5B2B63A8, 0x559535D5, 0x7511479E, +0xEBE215E5, 0x30C64B94, 0x14A84A6F, 0x9C869123, 0xCC394C6A, 0xFF4A5F8A, +0x904D0406, 0xDDBBEE99, 0x52CA1E11, 0xC418AAFF, 0x6998EB64, 0xFCFF07FE, +0x5E018B34, 0x0EBE567D, 0x9BD9BAE7, 0xC1324263, 0xDC7B75B5, 0x44179726, +0xCB6667AE, 0x0CCB9525, 0x9567EC9A, 0x2AD05786, 0x37996050, 0xD305B8E4, +0x83BA65AD, 0xAE3519EF, 0xC913A4F6, 0x4AA9C15B, 0x1BD6873E, 0x595EA0F0, +0x8A5B1814, 0x703BAF02, 0xE076AB04, 0x50BFDD49, 0x1863DF4A, 0xB656C6A5, +0x530A853D, 0x1237FA87, 0x94A777B6, 0x517F4665, 0xB109ED61, 0xE6E91BEC, +0x8525D545, 0x3B52F575, 0x413D7FBA, 0x428827CE, 0x4E43B2EB, 0xE997D6BD, +0x9EF3527B, 0x7F456253, 0xFBA02C3A, 0xD1707BBC, 0xF76BB91F, 0x171D121B, +0xEEC8FD79, 0x7CF03A27, 0x45D70C0A, 0x607996DD, 0xF6AB2233, 0x1C89ACFA, +0xBB5DC8AC, 0x7D30A10B, 0xA14BD4BE, 0x0B94BEE1, 0x0A5425CD, 0x4662547E, +0x1182A2F3, 0xA33E17E6, 0x66E62635, 0x0275C358, 0x8B9B8338, 0xBDC27844, +0x48DC0203, 0xA08B4F92, 0xB37C2E39, 0x84E54E69, 0x8F71F088, 0x3927362D, +0xFD3F9CD2, 0x246E01FB, 0x16DD8937, 0x00000000, 0x57E0F68D, 0x986CE293, +0xF815744E, 0xD45A9320, 0x38E7AD01, 0x5DB4D340, 0xC2871A17, 0x6A2DB310, +0xD62F5078, 0x1F3CF48E, 0xA5A1A70E, 0x4C3671B3, 0x25AE9AD7, 0xDB245E71, +0x8750161D, 0xF9D5EF62, 0x86908D31, 0x1A161C12, 0x81CFA6F5, 0x6F075B8C, +0x1D4937D6, 0x3A926E59, 0x776484C6, 0x3FB886C5, 0xCDF9D746, 0xD0B0E090, +0x4F8329C7, 0x40FDE496, 0x0D0B0E09, 0x56206DA1, 0xEA228EC9, 0x882EDB4C, +0x738EF776, 0xB2BCB515, 0x5FC11018, 0xA96A322B, 0x8EB16BA4, 0x5455AEF9, +0x89EE4060, 0xEF086655, 0x2144E967, 0xECBD3E21, 0xBE772030, 0xC7ADF28B, +0xE72980C0, 0xCF8C141E, 0x4348BCE2, 0xFE8AC4A6, 0xC5D831D3, 0xFA60B716, +0xBA9D5380, 0xC0F2D94F, 0x3E781DE9, 0x2E3A2436, 0xF4DEE16B, 0xD7EFCB54, +0xF1F409F7, 0xAFF582C3, 0xB9280BF4, 0xD9519D29, 0x9238C75E, 0x5AEBF884, +0xB8E890D8, 0x3C0DDEB1, 0x8D0433D0, 0xE203685C, 0xDAE4C55D, 0x589E3BDC, +0x9D460A0F, 0xC8D33FDA, 0x27DB598F, 0x8CC4A8FC, 0x99AC79BF, 0x724E6C5A, +0xA2FE8CCA, 0xB5E39ED1, 0x76A41FEA, 0x04EA73B0 }; + +const u32bit Square::TD3[256] = { +0x68BC02E3, 0x85620C55, 0x3F23312A, 0xAB13F761, 0xD46D7298, 0xCB9A1921, +0x22A4613C, 0x9D3DCD45, 0xFDB42305, 0xC4075F2B, 0x2C01C09B, 0xD9800F3D, +0x6C5C7448, 0x7F7E85F9, 0x73AB1FF1, 0xEDDE0EB6, 0x3C6BED28, 0x97781A49, +0x2A918D9F, 0x579F33C9, 0x07A8AAA9, 0x0DED7DA5, 0x422D8F7C, 0x4DB0C976, +0x91E8574D, 0xA963CCCE, 0xEE96D2B4, 0x28E1B630, 0xF161B90D, 0x196726BD, +0x9BAD8041, 0xA06EC7C0, 0x83F24151, 0xDBF03492, 0xA21EFC6F, 0x32CE4C8F, +0xE0337313, 0xA7C66D69, 0x6D6493E5, 0x1A2FFABF, 0x1CBFB7BB, 0x7403B558, +0x6E2C4FE7, 0x89B7965D, 0x9C052AE8, 0x6619A344, 0x2E71FB34, 0xF229650F, +0x81827AFE, 0x1322F1B1, 0x0835ECA3, 0x510F7ECD, 0x7AA614FF, 0x7293F85C, +0xC297122F, 0x70E3C3F3, 0x2F491C99, 0x431568D1, 0xA3261BC2, 0xCC32B388, +0xCF7A6F8A, 0xE8069FB0, 0x47F51E7A, 0xBB79DAD2, 0x950821E6, 0x98E55C43, +0xB83106D0, 0xE37BAF11, 0x4165537E, 0xAA2B10CC, 0xB4E49CD8, 0x56A7D464, +0x7C3659FB, 0x4B208472, 0x9F4DF6EA, 0x5FAADF6A, 0xC1DFCE2D, 0x48685870, +0xAFF381CA, 0x05D89106, 0x774B695A, 0xDE28A594, 0xDF104239, 0x3BC34781, +0x82CAA6FC, 0xC8D2C523, 0xF86CB203, 0x0CD59A08, 0xB7AC40DA, 0xB909E17D, +0x24342C38, 0x5247A2CF, 0xB274D1DC, 0xA85B2B63, 0xD5559535, 0x9E751147, +0xE5EBE215, 0x9430C64B, 0x6F14A84A, 0x239C8691, 0x6ACC394C, 0x8AFF4A5F, +0x06904D04, 0x99DDBBEE, 0x1152CA1E, 0xFFC418AA, 0x646998EB, 0xFEFCFF07, +0x345E018B, 0x7D0EBE56, 0xE79BD9BA, 0x63C13242, 0xB5DC7B75, 0x26441797, +0xAECB6667, 0x250CCB95, 0x9A9567EC, 0x862AD057, 0x50379960, 0xE4D305B8, +0xAD83BA65, 0xEFAE3519, 0xF6C913A4, 0x5B4AA9C1, 0x3E1BD687, 0xF0595EA0, +0x148A5B18, 0x02703BAF, 0x04E076AB, 0x4950BFDD, 0x4A1863DF, 0xA5B656C6, +0x3D530A85, 0x871237FA, 0xB694A777, 0x65517F46, 0x61B109ED, 0xECE6E91B, +0x458525D5, 0x753B52F5, 0xBA413D7F, 0xCE428827, 0xEB4E43B2, 0xBDE997D6, +0x7B9EF352, 0x537F4562, 0x3AFBA02C, 0xBCD1707B, 0x1FF76BB9, 0x1B171D12, +0x79EEC8FD, 0x277CF03A, 0x0A45D70C, 0xDD607996, 0x33F6AB22, 0xFA1C89AC, +0xACBB5DC8, 0x0B7D30A1, 0xBEA14BD4, 0xE10B94BE, 0xCD0A5425, 0x7E466254, +0xF31182A2, 0xE6A33E17, 0x3566E626, 0x580275C3, 0x388B9B83, 0x44BDC278, +0x0348DC02, 0x92A08B4F, 0x39B37C2E, 0x6984E54E, 0x888F71F0, 0x2D392736, +0xD2FD3F9C, 0xFB246E01, 0x3716DD89, 0x00000000, 0x8D57E0F6, 0x93986CE2, +0x4EF81574, 0x20D45A93, 0x0138E7AD, 0x405DB4D3, 0x17C2871A, 0x106A2DB3, +0x78D62F50, 0x8E1F3CF4, 0x0EA5A1A7, 0xB34C3671, 0xD725AE9A, 0x71DB245E, +0x1D875016, 0x62F9D5EF, 0x3186908D, 0x121A161C, 0xF581CFA6, 0x8C6F075B, +0xD61D4937, 0x593A926E, 0xC6776484, 0xC53FB886, 0x46CDF9D7, 0x90D0B0E0, +0xC74F8329, 0x9640FDE4, 0x090D0B0E, 0xA156206D, 0xC9EA228E, 0x4C882EDB, +0x76738EF7, 0x15B2BCB5, 0x185FC110, 0x2BA96A32, 0xA48EB16B, 0xF95455AE, +0x6089EE40, 0x55EF0866, 0x672144E9, 0x21ECBD3E, 0x30BE7720, 0x8BC7ADF2, +0xC0E72980, 0x1ECF8C14, 0xE24348BC, 0xA6FE8AC4, 0xD3C5D831, 0x16FA60B7, +0x80BA9D53, 0x4FC0F2D9, 0xE93E781D, 0x362E3A24, 0x6BF4DEE1, 0x54D7EFCB, +0xF7F1F409, 0xC3AFF582, 0xF4B9280B, 0x29D9519D, 0x5E9238C7, 0x845AEBF8, +0xD8B8E890, 0xB13C0DDE, 0xD08D0433, 0x5CE20368, 0x5DDAE4C5, 0xDC589E3B, +0x0F9D460A, 0xDAC8D33F, 0x8F27DB59, 0xFC8CC4A8, 0xBF99AC79, 0x5A724E6C, +0xCAA2FE8C, 0xD1B5E39E, 0xEA76A41F, 0xB004EA73 }; + +} diff --git a/src/lib/block/square/square.cpp b/src/lib/block/square/square.cpp new file mode 100644 index 000000000..544f809fc --- /dev/null +++ b/src/lib/block/square/square.cpp @@ -0,0 +1,221 @@ +/* +* Square +* (C) 1999-2007 Jack Lloyd +* +* Based on the public domain reference implemenation +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Square Encryption +*/ +void Square::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0, B1, B2, B3; + + B0 = TE0[in[ 0] ^ ME[ 0]] ^ TE1[in[ 4] ^ ME[ 4]] ^ + TE2[in[ 8] ^ ME[ 8]] ^ TE3[in[12] ^ ME[12]] ^ EK[0]; + B1 = TE0[in[ 1] ^ ME[ 1]] ^ TE1[in[ 5] ^ ME[ 5]] ^ + TE2[in[ 9] ^ ME[ 9]] ^ TE3[in[13] ^ ME[13]] ^ EK[1]; + B2 = TE0[in[ 2] ^ ME[ 2]] ^ TE1[in[ 6] ^ ME[ 6]] ^ + TE2[in[10] ^ ME[10]] ^ TE3[in[14] ^ ME[14]] ^ EK[2]; + B3 = TE0[in[ 3] ^ ME[ 3]] ^ TE1[in[ 7] ^ ME[ 7]] ^ + TE2[in[11] ^ ME[11]] ^ TE3[in[15] ^ ME[15]] ^ EK[3]; + + for(size_t j = 1; j != 7; j += 2) + { + u32bit T0, T1, T2, T3; + T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(0, B1)] ^ + TE2[get_byte(0, B2)] ^ TE3[get_byte(0, B3)] ^ EK[4*j+0]; + T1 = TE0[get_byte(1, B0)] ^ TE1[get_byte(1, B1)] ^ + TE2[get_byte(1, B2)] ^ TE3[get_byte(1, B3)] ^ EK[4*j+1]; + T2 = TE0[get_byte(2, B0)] ^ TE1[get_byte(2, B1)] ^ + TE2[get_byte(2, B2)] ^ TE3[get_byte(2, B3)] ^ EK[4*j+2]; + T3 = TE0[get_byte(3, B0)] ^ TE1[get_byte(3, B1)] ^ + TE2[get_byte(3, B2)] ^ TE3[get_byte(3, B3)] ^ EK[4*j+3]; + + B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(0, T1)] ^ + TE2[get_byte(0, T2)] ^ TE3[get_byte(0, T3)] ^ EK[4*j+4]; + B1 = TE0[get_byte(1, T0)] ^ TE1[get_byte(1, T1)] ^ + TE2[get_byte(1, T2)] ^ TE3[get_byte(1, T3)] ^ EK[4*j+5]; + B2 = TE0[get_byte(2, T0)] ^ TE1[get_byte(2, T1)] ^ + TE2[get_byte(2, T2)] ^ TE3[get_byte(2, T3)] ^ EK[4*j+6]; + B3 = TE0[get_byte(3, T0)] ^ TE1[get_byte(3, T1)] ^ + TE2[get_byte(3, T2)] ^ TE3[get_byte(3, T3)] ^ EK[4*j+7]; + } + + out[ 0] = SE[get_byte(0, B0)] ^ ME[16]; + out[ 1] = SE[get_byte(0, B1)] ^ ME[17]; + out[ 2] = SE[get_byte(0, B2)] ^ ME[18]; + out[ 3] = SE[get_byte(0, B3)] ^ ME[19]; + out[ 4] = SE[get_byte(1, B0)] ^ ME[20]; + out[ 5] = SE[get_byte(1, B1)] ^ ME[21]; + out[ 6] = SE[get_byte(1, B2)] ^ ME[22]; + out[ 7] = SE[get_byte(1, B3)] ^ ME[23]; + out[ 8] = SE[get_byte(2, B0)] ^ ME[24]; + out[ 9] = SE[get_byte(2, B1)] ^ ME[25]; + out[10] = SE[get_byte(2, B2)] ^ ME[26]; + out[11] = SE[get_byte(2, B3)] ^ ME[27]; + out[12] = SE[get_byte(3, B0)] ^ ME[28]; + out[13] = SE[get_byte(3, B1)] ^ ME[29]; + out[14] = SE[get_byte(3, B2)] ^ ME[30]; + out[15] = SE[get_byte(3, B3)] ^ ME[31]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Square Decryption +*/ +void Square::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0, B1, B2, B3; + + B0 = TD0[in[ 0] ^ MD[ 0]] ^ TD1[in[ 4] ^ MD[ 4]] ^ + TD2[in[ 8] ^ MD[ 8]] ^ TD3[in[12] ^ MD[12]] ^ DK[0]; + B1 = TD0[in[ 1] ^ MD[ 1]] ^ TD1[in[ 5] ^ MD[ 5]] ^ + TD2[in[ 9] ^ MD[ 9]] ^ TD3[in[13] ^ MD[13]] ^ DK[1]; + B2 = TD0[in[ 2] ^ MD[ 2]] ^ TD1[in[ 6] ^ MD[ 6]] ^ + TD2[in[10] ^ MD[10]] ^ TD3[in[14] ^ MD[14]] ^ DK[2]; + B3 = TD0[in[ 3] ^ MD[ 3]] ^ TD1[in[ 7] ^ MD[ 7]] ^ + TD2[in[11] ^ MD[11]] ^ TD3[in[15] ^ MD[15]] ^ DK[3]; + + for(size_t j = 1; j != 7; j += 2) + { + u32bit T0, T1, T2, T3; + T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(0, B1)] ^ + TD2[get_byte(0, B2)] ^ TD3[get_byte(0, B3)] ^ DK[4*j+0]; + T1 = TD0[get_byte(1, B0)] ^ TD1[get_byte(1, B1)] ^ + TD2[get_byte(1, B2)] ^ TD3[get_byte(1, B3)] ^ DK[4*j+1]; + T2 = TD0[get_byte(2, B0)] ^ TD1[get_byte(2, B1)] ^ + TD2[get_byte(2, B2)] ^ TD3[get_byte(2, B3)] ^ DK[4*j+2]; + T3 = TD0[get_byte(3, B0)] ^ TD1[get_byte(3, B1)] ^ + TD2[get_byte(3, B2)] ^ TD3[get_byte(3, B3)] ^ DK[4*j+3]; + + B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(0, T1)] ^ + TD2[get_byte(0, T2)] ^ TD3[get_byte(0, T3)] ^ DK[4*j+4]; + B1 = TD0[get_byte(1, T0)] ^ TD1[get_byte(1, T1)] ^ + TD2[get_byte(1, T2)] ^ TD3[get_byte(1, T3)] ^ DK[4*j+5]; + B2 = TD0[get_byte(2, T0)] ^ TD1[get_byte(2, T1)] ^ + TD2[get_byte(2, T2)] ^ TD3[get_byte(2, T3)] ^ DK[4*j+6]; + B3 = TD0[get_byte(3, T0)] ^ TD1[get_byte(3, T1)] ^ + TD2[get_byte(3, T2)] ^ TD3[get_byte(3, T3)] ^ DK[4*j+7]; + } + + out[ 0] = SD[get_byte(0, B0)] ^ MD[16]; + out[ 1] = SD[get_byte(0, B1)] ^ MD[17]; + out[ 2] = SD[get_byte(0, B2)] ^ MD[18]; + out[ 3] = SD[get_byte(0, B3)] ^ MD[19]; + out[ 4] = SD[get_byte(1, B0)] ^ MD[20]; + out[ 5] = SD[get_byte(1, B1)] ^ MD[21]; + out[ 6] = SD[get_byte(1, B2)] ^ MD[22]; + out[ 7] = SD[get_byte(1, B3)] ^ MD[23]; + out[ 8] = SD[get_byte(2, B0)] ^ MD[24]; + out[ 9] = SD[get_byte(2, B1)] ^ MD[25]; + out[10] = SD[get_byte(2, B2)] ^ MD[26]; + out[11] = SD[get_byte(2, B3)] ^ MD[27]; + out[12] = SD[get_byte(3, B0)] ^ MD[28]; + out[13] = SD[get_byte(3, B1)] ^ MD[29]; + out[14] = SD[get_byte(3, B2)] ^ MD[30]; + out[15] = SD[get_byte(3, B3)] ^ MD[31]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Square Key Schedule +*/ +void Square::key_schedule(const byte key[], size_t) + { + secure_vector XEK(36), XDK(36); + + for(size_t i = 0; i != 4; ++i) + XEK[i] = load_be(key, i); + + for(size_t i = 0; i != 8; ++i) + { + XEK[4*i+4] = XEK[4*i ] ^ rotate_left(XEK[4*i+3], 8) ^ (0x01000000 << i); + XEK[4*i+5] = XEK[4*i+1] ^ XEK[4*i+4]; + XEK[4*i+6] = XEK[4*i+2] ^ XEK[4*i+5]; + XEK[4*i+7] = XEK[4*i+3] ^ XEK[4*i+6]; + + for(size_t j = 0; j != 4; ++j) + XDK[28 - 4*i + j] = XEK[4*(i+1)+j]; + + transform(&XEK[4*i]); + } + + EK.assign(&XEK[4], &XEK[36]); + DK.assign(&XDK[4], &XDK[36]); + + ME.resize(32); + MD.resize(32); + + for(size_t i = 0; i != 4; ++i) + for(size_t j = 0; j != 4; ++j) + { + ME[4*i+j ] = get_byte(j, XEK[i ]); + ME[4*i+j+16] = get_byte(j, XEK[i+32]); + MD[4*i+j ] = get_byte(j, XDK[i ]); + MD[4*i+j+16] = get_byte(j, XEK[i ]); + } + } + +/* +* Square's Inverse Linear Transformation +*/ +void Square::transform(u32bit round_key[4]) + { + static const byte G[4][4] = { + { 2, 1, 1, 3 }, + { 3, 2, 1, 1 }, + { 1, 3, 2, 1 }, + { 1, 1, 3, 2 } }; + + for(size_t i = 0; i != 4; ++i) + { + byte A[4] = { 0 }, B[4] = { 0 }; + + store_be(round_key[i], A); + + for(size_t j = 0; j != 4; ++j) + for(size_t k = 0; k != 4; ++k) + { + const byte a = A[k]; + const byte b = G[k][j]; + + if(a && b) + B[j] ^= ALog[(Log[a] + Log[b]) % 255]; + } + + round_key[i] = load_be(B, 0); + } + } + +/* +* Clear memory of sensitive data +*/ +void Square::clear() + { + zap(EK); + zap(DK); + zap(ME); + zap(MD); + } + +} diff --git a/src/lib/block/square/square.h b/src/lib/block/square/square.h new file mode 100644 index 000000000..618dbf6d9 --- /dev/null +++ b/src/lib/block/square/square.h @@ -0,0 +1,52 @@ +/* +* Square +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SQUARE_H__ +#define BOTAN_SQUARE_H__ + +#include + +namespace Botan { + +/** +* Square +*/ +class BOTAN_DLL Square : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Square"; } + BlockCipher* clone() const { return new Square; } + private: + void key_schedule(const byte[], size_t); + + static void transform(u32bit[4]); + + static const byte SE[256]; + static const byte SD[256]; + static const byte Log[256]; + static const byte ALog[255]; + + static const u32bit TE0[256]; + static const u32bit TE1[256]; + static const u32bit TE2[256]; + static const u32bit TE3[256]; + static const u32bit TD0[256]; + static const u32bit TD1[256]; + static const u32bit TD2[256]; + static const u32bit TD3[256]; + + secure_vector EK, DK; + secure_vector ME, MD; + }; + +} + +#endif diff --git a/src/lib/block/tea/info.txt b/src/lib/block/tea/info.txt new file mode 100644 index 000000000..14edfdb03 --- /dev/null +++ b/src/lib/block/tea/info.txt @@ -0,0 +1 @@ +define TEA 20131128 diff --git a/src/lib/block/tea/tea.cpp b/src/lib/block/tea/tea.cpp new file mode 100644 index 000000000..2accab700 --- /dev/null +++ b/src/lib/block/tea/tea.cpp @@ -0,0 +1,78 @@ +/* +* TEA +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* TEA Encryption +*/ +void TEA::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + u32bit S = 0; + for(size_t j = 0; j != 32; ++j) + { + S += 0x9E3779B9; + L += ((R << 4) + K[0]) ^ (R + S) ^ ((R >> 5) + K[1]); + R += ((L << 4) + K[2]) ^ (L + S) ^ ((L >> 5) + K[3]); + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TEA Decryption +*/ +void TEA::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + u32bit S = 0xC6EF3720; + for(size_t j = 0; j != 32; ++j) + { + R -= ((L << 4) + K[2]) ^ (L + S) ^ ((L >> 5) + K[3]); + L -= ((R << 4) + K[0]) ^ (R + S) ^ ((R >> 5) + K[1]); + S -= 0x9E3779B9; + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TEA Key Schedule +*/ +void TEA::key_schedule(const byte key[], size_t) + { + K.resize(4); + for(size_t i = 0; i != 4; ++i) + K[i] = load_be(key, i); + } + +void TEA::clear() + { + zap(K); + } + +} diff --git a/src/lib/block/tea/tea.h b/src/lib/block/tea/tea.h new file mode 100644 index 000000000..0d203975e --- /dev/null +++ b/src/lib/block/tea/tea.h @@ -0,0 +1,34 @@ +/* +* TEA +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TEA_H__ +#define BOTAN_TEA_H__ + +#include + +namespace Botan { + +/** +* TEA +*/ +class BOTAN_DLL TEA : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "TEA"; } + BlockCipher* clone() const { return new TEA; } + private: + void key_schedule(const byte[], size_t); + secure_vector K; + }; + +} + +#endif diff --git a/src/lib/block/threefish/info.txt b/src/lib/block/threefish/info.txt new file mode 100644 index 000000000..15843cdd3 --- /dev/null +++ b/src/lib/block/threefish/info.txt @@ -0,0 +1 @@ +define THREEFISH_512 20131224 diff --git a/src/lib/block/threefish/threefish.cpp b/src/lib/block/threefish/threefish.cpp new file mode 100644 index 000000000..587a76a12 --- /dev/null +++ b/src/lib/block/threefish/threefish.cpp @@ -0,0 +1,205 @@ +/* +* Threefish-512 +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +void Threefish_512::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + BOTAN_ASSERT(m_K.size() == 9, "Key was set"); + BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); + +#define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X0 += X4; \ + X1 += X5; \ + X2 += X6; \ + X3 += X7; \ + X4 = rotate_left(X4, ROT1); \ + X5 = rotate_left(X5, ROT2); \ + X6 = rotate_left(X6, ROT3); \ + X7 = rotate_left(X7, ROT4); \ + X4 ^= X0; \ + X5 ^= X1; \ + X6 ^= X2; \ + X7 ^= X3; \ + } while(0) + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 += m_K[(r ) % 9]; \ + X1 += m_K[(r+1) % 9]; \ + X2 += m_K[(r+2) % 9]; \ + X3 += m_K[(r+3) % 9]; \ + X4 += m_K[(r+4) % 9]; \ + X5 += m_K[(r+5) % 9] + m_T[(r ) % 3]; \ + X6 += m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ + X7 += m_K[(r+7) % 9] + (r); \ + } while(0) + +#define THREEFISH_ENC_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22); \ + THREEFISH_INJECT_KEY(R2); \ + } while(0) + + for(size_t i = 0; i != blocks; ++i) + { + u64bit X0 = load_le(in, 0); + u64bit X1 = load_le(in, 1); + u64bit X2 = load_le(in, 2); + u64bit X3 = load_le(in, 3); + u64bit X4 = load_le(in, 4); + u64bit X5 = load_le(in, 5); + u64bit X6 = load_le(in, 6); + u64bit X7 = load_le(in, 7); + + THREEFISH_INJECT_KEY(0); + + THREEFISH_ENC_8_ROUNDS(1,2); + THREEFISH_ENC_8_ROUNDS(3,4); + THREEFISH_ENC_8_ROUNDS(5,6); + THREEFISH_ENC_8_ROUNDS(7,8); + THREEFISH_ENC_8_ROUNDS(9,10); + THREEFISH_ENC_8_ROUNDS(11,12); + THREEFISH_ENC_8_ROUNDS(13,14); + THREEFISH_ENC_8_ROUNDS(15,16); + THREEFISH_ENC_8_ROUNDS(17,18); + + store_le(out, X0, X1, X2, X3, X4, X5, X6, X7); + + in += 64; + out += 64; + } + +#undef THREEFISH_ENC_8_ROUNDS +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_ROUND + } + +void Threefish_512::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + BOTAN_ASSERT(m_K.size() == 9, "Key was set"); + BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); + +#define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X4 ^= X0; \ + X5 ^= X1; \ + X6 ^= X2; \ + X7 ^= X3; \ + X4 = rotate_right(X4, ROT1); \ + X5 = rotate_right(X5, ROT2); \ + X6 = rotate_right(X6, ROT3); \ + X7 = rotate_right(X7, ROT4); \ + X0 -= X4; \ + X1 -= X5; \ + X2 -= X6; \ + X3 -= X7; \ + } while(0) + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 -= m_K[(r ) % 9]; \ + X1 -= m_K[(r+1) % 9]; \ + X2 -= m_K[(r+2) % 9]; \ + X3 -= m_K[(r+3) % 9]; \ + X4 -= m_K[(r+4) % 9]; \ + X5 -= m_K[(r+5) % 9] + m_T[(r ) % 3]; \ + X6 -= m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ + X7 -= m_K[(r+7) % 9] + (r); \ + } while(0) + +#define THREEFISH_DEC_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \ + THREEFISH_INJECT_KEY(R2); \ + } while(0) + + for(size_t i = 0; i != blocks; ++i) + { + u64bit X0 = load_le(in, 0); + u64bit X1 = load_le(in, 1); + u64bit X2 = load_le(in, 2); + u64bit X3 = load_le(in, 3); + u64bit X4 = load_le(in, 4); + u64bit X5 = load_le(in, 5); + u64bit X6 = load_le(in, 6); + u64bit X7 = load_le(in, 7); + + THREEFISH_INJECT_KEY(18); + + THREEFISH_DEC_8_ROUNDS(17,16); + THREEFISH_DEC_8_ROUNDS(15,14); + THREEFISH_DEC_8_ROUNDS(13,12); + THREEFISH_DEC_8_ROUNDS(11,10); + THREEFISH_DEC_8_ROUNDS(9,8); + THREEFISH_DEC_8_ROUNDS(7,6); + THREEFISH_DEC_8_ROUNDS(5,4); + THREEFISH_DEC_8_ROUNDS(3,2); + THREEFISH_DEC_8_ROUNDS(1,0); + + store_le(out, X0, X1, X2, X3, X4, X5, X6, X7); + + in += 64; + out += 64; + } + +#undef THREEFISH_DEC_8_ROUNDS +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_ROUND + } + +void Threefish_512::set_tweak(const byte tweak[], size_t len) + { + if(len != 16) + throw std::runtime_error("Unsupported twofish tweak length"); + m_T[0] = load_le(tweak, 0); + m_T[1] = load_le(tweak, 1); + m_T[2] = m_T[0] ^ m_T[1]; + } + +void Threefish_512::key_schedule(const byte key[], size_t) + { + // todo: define key schedule for smaller keys + m_K.resize(9); + + for(size_t i = 0; i != 8; ++i) + m_K[i] = load_le(key, i); + + m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ + m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; + } + +void Threefish_512::clear() + { + zeroise(m_K); + zeroise(m_T); + } + +} diff --git a/src/lib/block/threefish/threefish.h b/src/lib/block/threefish/threefish.h new file mode 100644 index 000000000..327e54843 --- /dev/null +++ b/src/lib/block/threefish/threefish.h @@ -0,0 +1,43 @@ +/* +* Threefish +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_THREEFISH_H__ +#define BOTAN_THREEFISH_H__ + +#include + +namespace Botan { + +/** +* Threefish-512 +*/ +class BOTAN_DLL Threefish_512 : public Block_Cipher_Fixed_Params<64, 64> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const override; + void decrypt_n(const byte in[], byte out[], size_t blocks) const override; + + void set_tweak(const byte tweak[], size_t len); + + void clear() override; + std::string name() const override { return "Threefish-512"; } + BlockCipher* clone() const override { return new Threefish_512; } + + Threefish_512() : m_T(3) {} + protected: + const secure_vector& get_T() const { return m_T; } + const secure_vector& get_K() const { return m_K; } + private: + void key_schedule(const byte key[], size_t key_len) override; + + secure_vector m_T; + secure_vector m_K; + }; + +} + +#endif diff --git a/src/lib/block/threefish_avx2/info.txt b/src/lib/block/threefish_avx2/info.txt new file mode 100644 index 000000000..3f62629b9 --- /dev/null +++ b/src/lib/block/threefish_avx2/info.txt @@ -0,0 +1,3 @@ +define THREEFISH_512_AVX2 20131224 + +need_isa avx2 diff --git a/src/lib/block/threefish_avx2/threefish_avx2.cpp b/src/lib/block/threefish_avx2/threefish_avx2.cpp new file mode 100644 index 000000000..9fad9bdcc --- /dev/null +++ b/src/lib/block/threefish_avx2/threefish_avx2.cpp @@ -0,0 +1,341 @@ +/* +* Threefish-512 +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +inline void interleave_epi64(__m256i& X0, __m256i& X1) + { + // interleave X0 and X1 qwords + // (X0,X1,X2,X3),(X4,X5,X6,X7) -> (X0,X2,X4,X6),(X1,X3,X5,X7) + + const __m256i T0 = _mm256_unpacklo_epi64(X0, X1); + const __m256i T1 = _mm256_unpackhi_epi64(X0, X1); + + X0 = _mm256_permute4x64_epi64(T0, _MM_SHUFFLE(3,1,2,0)); + X1 = _mm256_permute4x64_epi64(T1, _MM_SHUFFLE(3,1,2,0)); + } + +inline void deinterleave_epi64(__m256i& X0, __m256i& X1) + { + const __m256i T0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(3,1,2,0)); + const __m256i T1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(3,1,2,0)); + + X0 = _mm256_unpacklo_epi64(T0, T1); + X1 = _mm256_unpackhi_epi64(T0, T1); + } + +} + +void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u64bit* K = &get_K()[0]; + const u64bit* T_64 = &get_T()[0]; + + const __m256i ROTATE_1 = _mm256_set_epi64x(37,19,36,46); + const __m256i ROTATE_2 = _mm256_set_epi64x(42,14,27,33); + const __m256i ROTATE_3 = _mm256_set_epi64x(39,36,49,17); + const __m256i ROTATE_4 = _mm256_set_epi64x(56,54, 9,44); + const __m256i ROTATE_5 = _mm256_set_epi64x(24,34,30,39); + const __m256i ROTATE_6 = _mm256_set_epi64x(17,10,50,13); + const __m256i ROTATE_7 = _mm256_set_epi64x(43,39,29,25); + const __m256i ROTATE_8 = _mm256_set_epi64x(22,56,35, 8); + +#define THREEFISH_ROUND(X0, X1, SHL) \ + do { \ + const __m256i SHR = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHL); \ + X0 = _mm256_add_epi64(X0, X1); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(0, 3, 2, 1)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + } while(0) + +#define THREEFISH_ROUND_2(X0, X1, X2, X3, SHL) \ + do { \ + const __m256i SHR = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHL); \ + X0 = _mm256_add_epi64(X0, X1); \ + X2 = _mm256_add_epi64(X2, X3); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X3 = _mm256_or_si256(_mm256_sllv_epi64(X3, SHL), _mm256_srlv_epi64(X3, SHR)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X3 = _mm256_xor_si256(X3, X2); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(0, 3, 2, 1)); \ + X2 = _mm256_permute4x64_epi64(X2, _MM_SHUFFLE(0, 3, 2, 1)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + X3 = _mm256_permute4x64_epi64(X3, _MM_SHUFFLE(1, 2, 3, 0)); \ + } while(0) + +#define THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + const __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_add_epi64(X0, K0); \ + X1 = _mm256_add_epi64(X1, K1); \ + X1 = _mm256_add_epi64(X1, R); \ + X0 = _mm256_add_epi64(X0, T0); \ + X1 = _mm256_add_epi64(X1, T1); \ + R = _mm256_add_epi64(R, ONE); \ + } while(0) + +#define THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_add_epi64(X0, K0); \ + X2 = _mm256_add_epi64(X2, K0); \ + X1 = _mm256_add_epi64(X1, K1); \ + X3 = _mm256_add_epi64(X3, K1); \ + T1 = _mm256_add_epi64(T1, R); \ + X0 = _mm256_add_epi64(X0, T0); \ + X2 = _mm256_add_epi64(X2, T0); \ + X1 = _mm256_add_epi64(X1, T1); \ + X3 = _mm256_add_epi64(X3, T1); \ + R = _mm256_add_epi64(R, ONE); \ + } while(0) + +#define THREEFISH_ENC_8_ROUNDS(X0, X1, R, K1, K2, K3, T0, T1, T2) \ + do { \ + THREEFISH_ROUND(X0, X1, ROTATE_1); \ + THREEFISH_ROUND(X0, X1, ROTATE_2); \ + THREEFISH_ROUND(X0, X1, ROTATE_3); \ + THREEFISH_ROUND(X0, X1, ROTATE_4); \ + THREEFISH_INJECT_KEY(X0, X1, R, K1, K2, T0, T1); \ + \ + THREEFISH_ROUND(X0, X1, ROTATE_5); \ + THREEFISH_ROUND(X0, X1, ROTATE_6); \ + THREEFISH_ROUND(X0, X1, ROTATE_7); \ + THREEFISH_ROUND(X0, X1, ROTATE_8); \ + THREEFISH_INJECT_KEY(X0, X1, R, K2, K3, T2, T0); \ + } while(0) + +#define THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K1, K2, K3, T0, T1, T2) \ + do { \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_1); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_2); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_3); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_4); \ + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K1, K2, T0, T1); \ + \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_5); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_6); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_7); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_8); \ + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K2, K3, T2, T0); \ + } while(0) + + /* + v1.0 key schedule: 9 ymm registers (only need 2 or 3) + (0,1,2,3),(4,5,6,7) [8] + then mutating with vpermq + */ + const __m256i K0 = _mm256_set_epi64x(K[6], K[4], K[2], K[0]); + const __m256i K1 = _mm256_set_epi64x(K[7], K[5], K[3], K[1]); + const __m256i K2 = _mm256_set_epi64x(K[8], K[6], K[4], K[2]); + const __m256i K3 = _mm256_set_epi64x(K[0], K[7], K[5], K[3]); + const __m256i K4 = _mm256_set_epi64x(K[1], K[8], K[6], K[4]); + const __m256i K5 = _mm256_set_epi64x(K[2], K[0], K[7], K[5]); + const __m256i K6 = _mm256_set_epi64x(K[3], K[1], K[8], K[6]); + const __m256i K7 = _mm256_set_epi64x(K[4], K[2], K[0], K[7]); + const __m256i K8 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]); + + const __m256i ONE = _mm256_set_epi64x(1, 0, 0, 0); + + const __m256i* in_mm = reinterpret_cast(in); + __m256i* out_mm = reinterpret_cast<__m256i*>(out); + + while(blocks >= 2) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + __m256i X2 = _mm256_loadu_si256(in_mm++); + __m256i X3 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + __m256i R = _mm256_set_epi64x(0, 0, 0, 0); + + interleave_epi64(X0, X1); + interleave_epi64(X2, X3); + + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, 2, 3); + + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K1,K2,K3, 1, 2, 3); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K3,K4,K5, 2, 3, 1); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K5,K6,K7, 3, 1, 2); + + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K7,K8,K0, 1, 2, 3); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K0,K1,K2, 2, 3, 1); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K2,K3,K4, 3, 1, 2); + + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K4,K5,K6, 1, 2, 3); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K6,K7,K8, 2, 3, 1); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K8,K0,K1, 3, 1, 2); + + deinterleave_epi64(X0, X1); + deinterleave_epi64(X2, X3); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + _mm256_storeu_si256(out_mm++, X2); + _mm256_storeu_si256(out_mm++, X3); + + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + __m256i R = _mm256_set_epi64x(0, 0, 0, 0); + + interleave_epi64(X0, X1); + + THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, 2, 3); + + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K1,K2,K3, 1, 2, 3); + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K3,K4,K5, 2, 3, 1); + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K5,K6,K7, 3, 1, 2); + + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K7,K8,K0, 1, 2, 3); + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K0,K1,K2, 2, 3, 1); + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K2,K3,K4, 3, 1, 2); + + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K4,K5,K6, 1, 2, 3); + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K6,K7,K8, 2, 3, 1); + THREEFISH_ENC_8_ROUNDS(X0, X1, R, K8,K0,K1, 3, 1, 2); + + deinterleave_epi64(X0, X1); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + } + +#undef THREEFISH_ENC_8_ROUNDS +#undef THREEFISH_ROUND +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_ENC_2_8_ROUNDS +#undef THREEFISH_ROUND_2 +#undef THREEFISH_INJECT_KEY_2 + } + +void Threefish_512_AVX2::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u64bit* K = &get_K()[0]; + const u64bit* T_64 = &get_T()[0]; + + const __m256i ROTATE_1 = _mm256_set_epi64x(37,19,36,46); + const __m256i ROTATE_2 = _mm256_set_epi64x(42,14,27,33); + const __m256i ROTATE_3 = _mm256_set_epi64x(39,36,49,17); + const __m256i ROTATE_4 = _mm256_set_epi64x(56,54, 9,44); + const __m256i ROTATE_5 = _mm256_set_epi64x(24,34,30,39); + const __m256i ROTATE_6 = _mm256_set_epi64x(17,10,50,13); + const __m256i ROTATE_7 = _mm256_set_epi64x(43,39,29,25); + const __m256i ROTATE_8 = _mm256_set_epi64x(22,56,35, 8); + +#define THREEFISH_ROUND(X0, X1, SHR) \ + do { \ + const __m256i SHL = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHR); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(2, 1, 0, 3)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X0 = _mm256_sub_epi64(X0, X1); \ + } while(0) + +#define THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + const __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_sub_epi64(X0, K0); \ + X1 = _mm256_sub_epi64(X1, K1); \ + X1 = _mm256_sub_epi64(X1, R); \ + R = _mm256_sub_epi64(R, ONE); \ + X0 = _mm256_sub_epi64(X0, T0); \ + X1 = _mm256_sub_epi64(X1, T1); \ + } while(0) + +#define THREEFISH_DEC_8_ROUNDS(X0, X1, R, K1, K2, K3, T0, T1, T2) \ + do { \ + THREEFISH_INJECT_KEY(X0, X1, R, K2, K3, T2, T0); \ + THREEFISH_ROUND(X0, X1, ROTATE_8); \ + THREEFISH_ROUND(X0, X1, ROTATE_7); \ + THREEFISH_ROUND(X0, X1, ROTATE_6); \ + THREEFISH_ROUND(X0, X1, ROTATE_5); \ + \ + THREEFISH_INJECT_KEY(X0, X1, R, K1, K2, T0, T1); \ + THREEFISH_ROUND(X0, X1, ROTATE_4); \ + THREEFISH_ROUND(X0, X1, ROTATE_3); \ + THREEFISH_ROUND(X0, X1, ROTATE_2); \ + THREEFISH_ROUND(X0, X1, ROTATE_1); \ + } while(0) + + /* + v1.0 key schedule: 9 ymm registers (only need 2 or 3) + (0,1,2,3),(4,5,6,7) [8] + then mutating with vpermq + */ + const __m256i K0 = _mm256_set_epi64x(K[6], K[4], K[2], K[0]); + const __m256i K1 = _mm256_set_epi64x(K[7], K[5], K[3], K[1]); + const __m256i K2 = _mm256_set_epi64x(K[8], K[6], K[4], K[2]); + const __m256i K3 = _mm256_set_epi64x(K[0], K[7], K[5], K[3]); + const __m256i K4 = _mm256_set_epi64x(K[1], K[8], K[6], K[4]); + const __m256i K5 = _mm256_set_epi64x(K[2], K[0], K[7], K[5]); + const __m256i K6 = _mm256_set_epi64x(K[3], K[1], K[8], K[6]); + const __m256i K7 = _mm256_set_epi64x(K[4], K[2], K[0], K[7]); + const __m256i K8 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]); + + const __m256i ONE = _mm256_set_epi64x(1, 0, 0, 0); + + const __m256i* in_mm = reinterpret_cast(in); + __m256i* out_mm = reinterpret_cast<__m256i*>(out); + + for(size_t i = 0; i != blocks; ++i) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + __m256i R = _mm256_set_epi64x(18, 0, 0, 0); + + interleave_epi64(X0, X1); + + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K8,K0,K1, 3, 1, 2); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K6,K7,K8, 2, 3, 1); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K4,K5,K6, 1, 2, 3); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K2,K3,K4, 3, 1, 2); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K0,K1,K2, 2, 3, 1); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K7,K8,K0, 1, 2, 3); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K5,K6,K7, 3, 1, 2); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K3,K4,K5, 2, 3, 1); + THREEFISH_DEC_8_ROUNDS(X0, X1, R, K1,K2,K3, 1, 2, 3); + + THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, 2, 3); + + deinterleave_epi64(X0, X1); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + } + +#undef THREEFISH_DEC_8_ROUNDS +#undef THREEFISH_ROUND +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_DEC_2_8_ROUNDS +#undef THREEFISH_ROUND_2 +#undef THREEFISH_INJECT_KEY_2 + } + +} diff --git a/src/lib/block/threefish_avx2/threefish_avx2.h b/src/lib/block/threefish_avx2/threefish_avx2.h new file mode 100644 index 000000000..ed0da00d6 --- /dev/null +++ b/src/lib/block/threefish_avx2/threefish_avx2.h @@ -0,0 +1,28 @@ +/* +* Threefish-512 in AVX2 +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_THREEFISH_AVX2_H__ +#define BOTAN_THREEFISH_AVX2_H__ + +#include + +namespace Botan { + +/** +* Threefish-512 +*/ +class BOTAN_DLL Threefish_512_AVX2 : public Threefish_512 + { + private: + void encrypt_n(const byte in[], byte out[], size_t blocks) const override; + void decrypt_n(const byte in[], byte out[], size_t blocks) const override; + BlockCipher* clone() const override { return new Threefish_512_AVX2; } + }; + +} + +#endif diff --git a/src/lib/block/twofish/info.txt b/src/lib/block/twofish/info.txt new file mode 100644 index 000000000..c4351db59 --- /dev/null +++ b/src/lib/block/twofish/info.txt @@ -0,0 +1 @@ +define TWOFISH 20131128 diff --git a/src/lib/block/twofish/two_tab.cpp b/src/lib/block/twofish/two_tab.cpp new file mode 100644 index 000000000..19ba58de6 --- /dev/null +++ b/src/lib/block/twofish/two_tab.cpp @@ -0,0 +1,293 @@ +/* +* S-Box and MDS Tables for Twofish +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const byte Twofish::Q0[256] = { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0 }; + +const byte Twofish::Q1[256] = { + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 }; + +const byte Twofish::RS[32] = { + 0x01, 0xA4, 0x02, 0xA4, 0xA4, 0x56, 0xA1, 0x55, 0x55, 0x82, 0xFC, 0x87, + 0x87, 0xF3, 0xC1, 0x5A, 0x5A, 0x1E, 0x47, 0x58, 0x58, 0xC6, 0xAE, 0xDB, + 0xDB, 0x68, 0x3D, 0x9E, 0x9E, 0xE5, 0x19, 0x03 }; + +const byte Twofish::EXP_TO_POLY[255] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2, + 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6, + 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A, + 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63, + 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C, + 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07, + 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88, + 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12, + 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7, + 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C, + 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8, + 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25, + 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A, + 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE, + 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC, + 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E, + 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92, + 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89, + 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB, + 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1, + 0x8F, 0x53, 0xA6 }; + +const byte Twofish::POLY_TO_EXP[255] = { + 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19, + 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A, + 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C, + 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B, + 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47, + 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D, + 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8, + 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C, + 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83, + 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48, + 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26, + 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E, + 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3, + 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9, + 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A, + 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D, + 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75, + 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84, + 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64, + 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49, + 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF, + 0x85, 0xC8, 0xA1 }; + +const u32bit Twofish::MDS0[256] = { + 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, + 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, + 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32, + 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, + 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, + 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, + 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1, + 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, + 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, + 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, + 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0, + 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, + 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, + 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, + 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3, + 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, + 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, + 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, + 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C, + 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, + 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, + 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, + 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72, + 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, + 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, + 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, + 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39, + 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, + 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, + 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, + 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5, + 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, + 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, + 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, + 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E, + 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, + 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, + 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, + 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2, + 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, + 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, + 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, + 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 }; + +const u32bit Twofish::MDS1[256] = { + 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, + 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, + 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020, + 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, + 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, + 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, + 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A, + 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, + 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, + 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, + 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9, + 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, + 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, + 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, + 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414, + 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, + 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, + 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, + 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5, + 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, + 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, + 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, + 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202, + 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, + 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, + 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, + 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808, + 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, + 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, + 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, + 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505, + 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, + 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, + 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, + 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF, + 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, + 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, + 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, + 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6, + 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, + 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, + 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, + 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 }; + +const u32bit Twofish::MDS2[256] = { + 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, + 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, + 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A, + 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, + 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, + 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, + 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB, + 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, + 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, + 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, + 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C, + 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, + 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, + 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, + 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035, + 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, + 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, + 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, + 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F, + 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, + 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, + 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, + 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA, + 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, + 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, + 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, + 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D, + 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, + 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, + 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, + 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086, + 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, + 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, + 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, + 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691, + 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, + 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, + 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, + 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E, + 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, + 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, + 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, + 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF }; + +const u32bit Twofish::MDS3[256] = { + 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, + 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, + 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643, + 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, + 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, + 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, + 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3, + 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, + 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, + 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, + 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF, + 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, + 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, + 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, + 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA, + 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, + 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, + 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, + 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D, + 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, + 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, + 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, + 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B, + 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, + 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, + 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, + 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE, + 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, + 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, + 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, + 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E, + 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, + 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, + 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, + 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718, + 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, + 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, + 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, + 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882, + 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, + 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, + 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, + 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 }; + +} diff --git a/src/lib/block/twofish/twofish.cpp b/src/lib/block/twofish/twofish.cpp new file mode 100644 index 000000000..4ea8a799e --- /dev/null +++ b/src/lib/block/twofish/twofish.cpp @@ -0,0 +1,245 @@ +/* +* Twofish +* (C) 1999-2007 Jack Lloyd +* +* The key schedule implemenation is based on a public domain +* implementation by Matthew Skala +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Twofish Encryption +*/ +void Twofish::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0) ^ RK[0]; + u32bit B = load_le(in, 1) ^ RK[1]; + u32bit C = load_le(in, 2) ^ RK[2]; + u32bit D = load_le(in, 3) ^ RK[3]; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit X, Y; + + X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ + SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; + Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ + SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; + X += Y; + Y += X + RK[2*j + 9]; + X += RK[2*j + 8]; + + C = rotate_right(C ^ X, 1); + D = rotate_left(D, 1) ^ Y; + + X = SB[ get_byte(3, C)] ^ SB[256+get_byte(2, C)] ^ + SB[512+get_byte(1, C)] ^ SB[768+get_byte(0, C)]; + Y = SB[ get_byte(0, D)] ^ SB[256+get_byte(3, D)] ^ + SB[512+get_byte(2, D)] ^ SB[768+get_byte(1, D)]; + X += Y; + Y += X + RK[2*j + 11]; + X += RK[2*j + 10]; + + A = rotate_right(A ^ X, 1); + B = rotate_left(B, 1) ^ Y; + } + + C ^= RK[4]; + D ^= RK[5]; + A ^= RK[6]; + B ^= RK[7]; + + store_le(out, C, D, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Twofish Decryption +*/ +void Twofish::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0) ^ RK[4]; + u32bit B = load_le(in, 1) ^ RK[5]; + u32bit C = load_le(in, 2) ^ RK[6]; + u32bit D = load_le(in, 3) ^ RK[7]; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit X, Y; + + X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ + SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; + Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ + SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; + X += Y; + Y += X + RK[39 - 2*j]; + X += RK[38 - 2*j]; + + C = rotate_left(C, 1) ^ X; + D = rotate_right(D ^ Y, 1); + + X = SB[ get_byte(3, C)] ^ SB[256+get_byte(2, C)] ^ + SB[512+get_byte(1, C)] ^ SB[768+get_byte(0, C)]; + Y = SB[ get_byte(0, D)] ^ SB[256+get_byte(3, D)] ^ + SB[512+get_byte(2, D)] ^ SB[768+get_byte(1, D)]; + X += Y; + Y += X + RK[37 - 2*j]; + X += RK[36 - 2*j]; + + A = rotate_left(A, 1) ^ X; + B = rotate_right(B ^ Y, 1); + } + + C ^= RK[0]; + D ^= RK[1]; + A ^= RK[2]; + B ^= RK[3]; + + store_le(out, C, D, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Twofish Key Schedule +*/ +void Twofish::key_schedule(const byte key[], size_t length) + { + SB.resize(1024); + RK.resize(40); + + secure_vector S(16); + + for(size_t i = 0; i != length; ++i) + rs_mul(&S[4*(i/8)], key[i], i); + + if(length == 16) + { + for(size_t i = 0; i != 256; ++i) + { + SB[ i] = MDS0[Q0[Q0[i]^S[ 0]]^S[ 4]]; + SB[256+i] = MDS1[Q0[Q1[i]^S[ 1]]^S[ 5]]; + SB[512+i] = MDS2[Q1[Q0[i]^S[ 2]]^S[ 6]]; + SB[768+i] = MDS3[Q1[Q1[i]^S[ 3]]^S[ 7]]; + } + + for(size_t i = 0; i != 40; i += 2) + { + u32bit X = MDS0[Q0[Q0[i ]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[i ]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[i ]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[i ]^key[11]]^key[ 3]]; + u32bit Y = MDS0[Q0[Q0[i+1]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[i+1]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[i+1]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[i+1]^key[15]]^key[ 7]]; + Y = rotate_left(Y, 8); + X += Y; Y += X; + + RK[i] = X; + RK[i+1] = rotate_left(Y, 9); + } + } + else if(length == 24) + { + for(size_t i = 0; i != 256; ++i) + { + SB[ i] = MDS0[Q0[Q0[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]; + SB[256+i] = MDS1[Q0[Q1[Q1[i]^S[ 1]]^S[ 5]]^S[ 9]]; + SB[512+i] = MDS2[Q1[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]; + SB[768+i] = MDS3[Q1[Q1[Q0[i]^S[ 3]]^S[ 7]]^S[11]]; + } + + for(size_t i = 0; i != 40; i += 2) + { + u32bit X = MDS0[Q0[Q0[Q1[i ]^key[16]]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[Q1[i ]^key[17]]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[Q0[i ]^key[18]]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[Q0[i ]^key[19]]^key[11]]^key[ 3]]; + u32bit Y = MDS0[Q0[Q0[Q1[i+1]^key[20]]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[Q1[i+1]^key[21]]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[Q0[i+1]^key[22]]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[Q0[i+1]^key[23]]^key[15]]^key[ 7]]; + Y = rotate_left(Y, 8); + X += Y; Y += X; + + RK[i] = X; + RK[i+1] = rotate_left(Y, 9); + } + } + else if(length == 32) + { + for(size_t i = 0; i != 256; ++i) + { + SB[ i] = MDS0[Q0[Q0[Q1[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]^S[12]]; + SB[256+i] = MDS1[Q0[Q1[Q1[Q0[i]^S[ 1]]^S[ 5]]^S[ 9]]^S[13]]; + SB[512+i] = MDS2[Q1[Q0[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]^S[14]]; + SB[768+i] = MDS3[Q1[Q1[Q0[Q1[i]^S[ 3]]^S[ 7]]^S[11]]^S[15]]; + } + + for(size_t i = 0; i != 40; i += 2) + { + u32bit X = MDS0[Q0[Q0[Q1[Q1[i ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[Q1[Q0[i ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[Q0[Q0[i ]^key[26]]^key[18]]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[Q0[Q1[i ]^key[27]]^key[19]]^key[11]]^key[ 3]]; + u32bit Y = MDS0[Q0[Q0[Q1[Q1[i+1]^key[28]]^key[20]]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[Q1[Q0[i+1]^key[29]]^key[21]]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[Q0[Q0[i+1]^key[30]]^key[22]]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[Q0[Q1[i+1]^key[31]]^key[23]]^key[15]]^key[ 7]]; + Y = rotate_left(Y, 8); + X += Y; Y += X; + + RK[i] = X; + RK[i+1] = rotate_left(Y, 9); + } + } + } + +/* +* Do one column of the RS matrix multiplcation +*/ +void Twofish::rs_mul(byte S[4], byte key, size_t offset) + { + if(key) + { + byte X = POLY_TO_EXP[key - 1]; + + byte RS1 = RS[(4*offset ) % 32]; + byte RS2 = RS[(4*offset+1) % 32]; + byte RS3 = RS[(4*offset+2) % 32]; + byte RS4 = RS[(4*offset+3) % 32]; + + S[0] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; + S[1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; + S[2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; + S[3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; + } + } + +/* +* Clear memory of sensitive data +*/ +void Twofish::clear() + { + zap(SB); + zap(RK); + } + +} diff --git a/src/lib/block/twofish/twofish.h b/src/lib/block/twofish/twofish.h new file mode 100644 index 000000000..3d8e47498 --- /dev/null +++ b/src/lib/block/twofish/twofish.h @@ -0,0 +1,47 @@ +/* +* Twofish +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TWOFISH_H__ +#define BOTAN_TWOFISH_H__ + +#include + +namespace Botan { + +/** +* Twofish, an AES finalist +*/ +class BOTAN_DLL Twofish : public Block_Cipher_Fixed_Params<16, 16, 32, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Twofish"; } + BlockCipher* clone() const { return new Twofish; } + private: + void key_schedule(const byte[], size_t); + + static void rs_mul(byte[4], byte, size_t); + + static const u32bit MDS0[256]; + static const u32bit MDS1[256]; + static const u32bit MDS2[256]; + static const u32bit MDS3[256]; + static const byte Q0[256]; + static const byte Q1[256]; + static const byte RS[32]; + static const byte EXP_TO_POLY[255]; + static const byte POLY_TO_EXP[255]; + + secure_vector SB, RK; + }; + +} + +#endif diff --git a/src/lib/block/xtea/info.txt b/src/lib/block/xtea/info.txt new file mode 100644 index 000000000..e2cc8ac34 --- /dev/null +++ b/src/lib/block/xtea/info.txt @@ -0,0 +1 @@ +define XTEA 20131128 diff --git a/src/lib/block/xtea/xtea.cpp b/src/lib/block/xtea/xtea.cpp new file mode 100644 index 000000000..165a6ea6a --- /dev/null +++ b/src/lib/block/xtea/xtea.cpp @@ -0,0 +1,146 @@ +/* +* XTEA +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +void xtea_encrypt_4(const byte in[32], byte out[32], const u32bit EK[64]) + { + u32bit L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t i = 0; i != 32; ++i) + { + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*i]; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*i]; + L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*i]; + L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*i]; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*i+1]; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*i+1]; + R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*i+1]; + R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*i+1]; + } + + store_be(out, L0, R0, L1, R1, L2, R2, L3, R3); + } + +void xtea_decrypt_4(const byte in[32], byte out[32], const u32bit EK[64]) + { + u32bit L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t i = 0; i != 32; ++i) + { + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*i]; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*i]; + R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*i]; + R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*i]; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*i]; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*i]; + L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*i]; + L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*i]; + } + + store_be(out, L0, R0, L1, R1, L2, R2, L3, R3); + } + +} + +/* +* XTEA Encryption +*/ +void XTEA::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + while(blocks >= 4) + { + xtea_encrypt_4(in, out, &(this->EK[0])); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 0; j != 32; ++j) + { + L += (((R << 4) ^ (R >> 5)) + R) ^ EK[2*j]; + R += (((L << 4) ^ (L >> 5)) + L) ^ EK[2*j+1]; + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* XTEA Decryption +*/ +void XTEA::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + while(blocks >= 4) + { + xtea_decrypt_4(in, out, &(this->EK[0])); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 0; j != 32; ++j) + { + R -= (((L << 4) ^ (L >> 5)) + L) ^ EK[63 - 2*j]; + L -= (((R << 4) ^ (R >> 5)) + R) ^ EK[62 - 2*j]; + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* XTEA Key Schedule +*/ +void XTEA::key_schedule(const byte key[], size_t) + { + EK.resize(64); + + secure_vector UK(4); + for(size_t i = 0; i != 4; ++i) + UK[i] = load_be(key, i); + + u32bit D = 0; + for(size_t i = 0; i != 64; i += 2) + { + EK[i ] = D + UK[D % 4]; + D += 0x9E3779B9; + EK[i+1] = D + UK[(D >> 11) % 4]; + } + } + +void XTEA::clear() + { + zap(EK); + } + +} diff --git a/src/lib/block/xtea/xtea.h b/src/lib/block/xtea/xtea.h new file mode 100644 index 000000000..42acc35a5 --- /dev/null +++ b/src/lib/block/xtea/xtea.h @@ -0,0 +1,40 @@ +/* +* XTEA +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_XTEA_H__ +#define BOTAN_XTEA_H__ + +#include + +namespace Botan { + +/** +* XTEA +*/ +class BOTAN_DLL XTEA : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "XTEA"; } + BlockCipher* clone() const { return new XTEA; } + protected: + /** + * @return const reference to the key schedule + */ + const secure_vector& get_EK() const { return EK; } + + private: + void key_schedule(const byte[], size_t); + secure_vector EK; + }; + +} + +#endif diff --git a/src/lib/block/xtea_simd/info.txt b/src/lib/block/xtea_simd/info.txt new file mode 100644 index 000000000..7e7d001ac --- /dev/null +++ b/src/lib/block/xtea_simd/info.txt @@ -0,0 +1,7 @@ +define XTEA_SIMD 20131128 + + +xtea +simd +simd_engine + diff --git a/src/lib/block/xtea_simd/xtea_simd.cpp b/src/lib/block/xtea_simd/xtea_simd.cpp new file mode 100644 index 000000000..d684eca5a --- /dev/null +++ b/src/lib/block/xtea_simd/xtea_simd.cpp @@ -0,0 +1,130 @@ +/* +* XTEA in SIMD +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +void xtea_encrypt_8(const byte in[64], byte out[64], const u32bit EK[64]) + { + SIMD_32 L0 = SIMD_32::load_be(in ); + SIMD_32 R0 = SIMD_32::load_be(in + 16); + SIMD_32 L1 = SIMD_32::load_be(in + 32); + SIMD_32 R1 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(L0, R0, L1, R1); + + for(size_t i = 0; i != 32; i += 2) + { + SIMD_32 K0(EK[2*i ]); + SIMD_32 K1(EK[2*i+1]); + SIMD_32 K2(EK[2*i+2]); + SIMD_32 K3(EK[2*i+3]); + + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K0; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K0; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K1; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K1; + + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K2; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K2; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K3; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K3; + } + + SIMD_32::transpose(L0, R0, L1, R1); + + L0.store_be(out); + R0.store_be(out + 16); + L1.store_be(out + 32); + R1.store_be(out + 48); + } + +void xtea_decrypt_8(const byte in[64], byte out[64], const u32bit EK[64]) + { + SIMD_32 L0 = SIMD_32::load_be(in ); + SIMD_32 R0 = SIMD_32::load_be(in + 16); + SIMD_32 L1 = SIMD_32::load_be(in + 32); + SIMD_32 R1 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(L0, R0, L1, R1); + + for(size_t i = 0; i != 32; i += 2) + { + SIMD_32 K0(EK[63 - 2*i]); + SIMD_32 K1(EK[62 - 2*i]); + SIMD_32 K2(EK[61 - 2*i]); + SIMD_32 K3(EK[60 - 2*i]); + + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K0; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K0; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K1; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K1; + + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K2; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K2; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K3; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K3; + } + + SIMD_32::transpose(L0, R0, L1, R1); + + L0.store_be(out); + R0.store_be(out + 16); + L1.store_be(out + 32); + R1.store_be(out + 48); + } + +} + +/* +* XTEA Encryption +*/ +void XTEA_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_EK()[0]); + + while(blocks >= 8) + { + xtea_encrypt_8(in, out, KS); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + + if(blocks) + XTEA::encrypt_n(in, out, blocks); + } + +/* +* XTEA Decryption +*/ +void XTEA_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_EK()[0]); + + while(blocks >= 8) + { + xtea_decrypt_8(in, out, KS); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + + if(blocks) + XTEA::decrypt_n(in, out, blocks); + } + +} diff --git a/src/lib/block/xtea_simd/xtea_simd.h b/src/lib/block/xtea_simd/xtea_simd.h new file mode 100644 index 000000000..ecfdf90a5 --- /dev/null +++ b/src/lib/block/xtea_simd/xtea_simd.h @@ -0,0 +1,30 @@ +/* +* XTEA in SIMD +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_XTEA_SIMD_H__ +#define BOTAN_XTEA_SIMD_H__ + +#include + +namespace Botan { + +/** +* XTEA implemented using SIMD operations +*/ +class BOTAN_DLL XTEA_SIMD : public XTEA + { + public: + size_t parallelism() const { return 8; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + BlockCipher* clone() const { return new XTEA_SIMD; } + }; + +} + +#endif diff --git a/src/lib/cert/cvc/asn1_eac_str.cpp b/src/lib/cert/cvc/asn1_eac_str.cpp new file mode 100644 index 000000000..2084a9c03 --- /dev/null +++ b/src/lib/cert/cvc/asn1_eac_str.cpp @@ -0,0 +1,127 @@ +/* +* Simple ASN.1 String Types +* (C) 2007 FlexSecure GmbH +* 2008-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an ASN1_EAC_String +*/ +ASN1_EAC_String::ASN1_EAC_String(const std::string& str, ASN1_Tag t) : tag(t) + { + iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); + + if(!sanity_check()) + throw Invalid_Argument("ASN1_EAC_String contains illegal characters"); + } + +/* +* Return this string in ISO 8859-1 encoding +*/ +std::string ASN1_EAC_String::iso_8859() const + { + return iso_8859_str; + } + +/* +* Return this string in local encoding +*/ +std::string ASN1_EAC_String::value() const + { + return Charset::transcode(iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET); + } + +/* +* Return the type of this string object +*/ +ASN1_Tag ASN1_EAC_String::tagging() const + { + return tag; + } + +/* +* DER encode an ASN1_EAC_String +*/ +void ASN1_EAC_String::encode_into(DER_Encoder& encoder) const + { + std::string value = iso_8859(); + encoder.add_object(tagging(), APPLICATION, value); + } + +/* +* Decode a BER encoded ASN1_EAC_String +*/ +void ASN1_EAC_String::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + + if(obj.type_tag != this->tag) + { + std::stringstream ss; + + ss << "ASN1_EAC_String tag mismatch, tag was " + << std::hex << obj.type_tag + << " expected " + << std::hex << this->tag; + + throw Decoding_Error(ss.str()); + } + + Character_Set charset_is; + charset_is = LATIN1_CHARSET; + + try + { + *this = ASN1_EAC_String( + Charset::transcode(ASN1::to_string(obj), charset_is, LOCAL_CHARSET), + obj.type_tag); + } + catch(Invalid_Argument& inv_arg) + { + throw Decoding_Error(std::string("ASN1_EAC_String decoding failed: ") + + inv_arg.what()); + } + } + +// checks for compliance to the alphabet defined in TR-03110 v1.10, 2007-08-20 +// p. 43 +bool ASN1_EAC_String::sanity_check() const + { + const byte* rep = reinterpret_cast(iso_8859_str.data()); + const size_t rep_len = iso_8859_str.size(); + + for(size_t i = 0; i != rep_len; ++i) + { + if((rep[i] < 0x20) || ((rep[i] >= 0x7F) && (rep[i] < 0xA0))) + return false; + } + + return true; + } + +bool operator==(const ASN1_EAC_String& lhs, const ASN1_EAC_String& rhs) + { + return (lhs.iso_8859() == rhs.iso_8859()); + } + +ASN1_Car::ASN1_Car(std::string const& str) + : ASN1_EAC_String(str, ASN1_Tag(2)) + {} + +ASN1_Chr::ASN1_Chr(std::string const& str) + : ASN1_EAC_String(str, ASN1_Tag(32)) + {} + +} diff --git a/src/lib/cert/cvc/asn1_eac_tm.cpp b/src/lib/cert/cvc/asn1_eac_tm.cpp new file mode 100644 index 000000000..e40f555b3 --- /dev/null +++ b/src/lib/cert/cvc/asn1_eac_tm.cpp @@ -0,0 +1,293 @@ +/* +* EAC Time Types +* (C) 2007 FlexSecure GmbH +* 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::vector enc_two_digit(u32bit in) + { + std::vector result; + in %= 100; + if(in < 10) + result.push_back(0x00); + else + { + u32bit y_first_pos = round_down(in, 10) / 10; + result.push_back(static_cast(y_first_pos)); + } + + u32bit y_sec_pos = in % 10; + result.push_back(static_cast(y_sec_pos)); + return result; + } + +u32bit dec_two_digit(byte b1, byte b2) + { + u32bit upper = b1; + u32bit lower = b2; + + if(upper > 9 || lower > 9) + throw Invalid_Argument("CVC dec_two_digit value too large"); + + return upper*10 + lower; + } + +} + +/* +* Create an EAC_Time +*/ +EAC_Time::EAC_Time(const std::chrono::system_clock::time_point& time, + ASN1_Tag t) : tag(t) + { + calendar_point cal = calendar_value(time); + + year = cal.year; + month = cal.month; + day = cal.day; + } + +/* +* Create an EAC_Time +*/ +EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t) : tag(t) + { + set_to(t_spec); + } + +/* +* Create an EAC_Time +*/ +EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t) : + year(y), month(m), day(d), tag(t) + { + } + +/* +* Set the time with a human readable string +*/ +void EAC_Time::set_to(const std::string& time_str) + { + if(time_str == "") + { + year = month = day = 0; + return; + } + + std::vector params; + std::string current; + + for(u32bit j = 0; j != time_str.size(); ++j) + { + if(Charset::is_digit(time_str[j])) + current += time_str[j]; + else + { + if(current != "") + params.push_back(current); + current.clear(); + } + } + if(current != "") + params.push_back(current); + + if(params.size() != 3) + throw Invalid_Argument("Invalid time specification " + time_str); + + year = to_u32bit(params[0]); + month = to_u32bit(params[1]); + day = to_u32bit(params[2]); + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + time_str); + } + + +/* +* DER encode a EAC_Time +*/ +void EAC_Time::encode_into(DER_Encoder& der) const + { + der.add_object(tag, APPLICATION, + encoded_eac_time()); + } + +/* +* Return a string representation of the time +*/ +std::string EAC_Time::as_string() const + { + if(time_is_set() == false) + throw Invalid_State("EAC_Time::as_string: No time set"); + + return std::to_string(year * 10000 + month * 100 + day); + } + +/* +* Return if the time has been set somehow +*/ +bool EAC_Time::time_is_set() const + { + return (year != 0); + } + +/* +* Return a human readable string representation +*/ +std::string EAC_Time::readable_string() const + { + if(time_is_set() == false) + throw Invalid_State("EAC_Time::readable_string: No time set"); + + std::string output(11, 0); + + std::sprintf(&output[0], "%04d/%02d/%02d", year, month, day); + + return output; + } + +/* +* Do a general sanity check on the time +*/ +bool EAC_Time::passes_sanity_check() const + { + if(year < 2000 || year > 2099) + return false; + if(month == 0 || month > 12) + return false; + if(day == 0 || day > 31) + return false; + + return true; + } + +/* +* modification functions +*/ +void EAC_Time::add_years(u32bit years) + { + year += years; + } + +void EAC_Time::add_months(u32bit months) + { + year += months/12; + month += months % 12; + if(month > 12) + { + year += 1; + month -= 12; + } + } + +/* +* Compare this time against another +*/ +s32bit EAC_Time::cmp(const EAC_Time& other) const + { + if(time_is_set() == false) + throw Invalid_State("EAC_Time::cmp: No time set"); + + const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0; + + if(year < other.year) return EARLIER; + if(year > other.year) return LATER; + if(month < other.month) return EARLIER; + if(month > other.month) return LATER; + if(day < other.day) return EARLIER; + if(day > other.day) return LATER; + + return SAME_TIME; + } + +/* +* Compare two EAC_Times for in various ways +*/ +bool operator==(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) == 0); + } + +bool operator!=(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) != 0); + } + +bool operator<=(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) <= 0); + } + +bool operator>=(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) >= 0); + } + +bool operator>(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) > 0); + } + +bool operator<(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) < 0); + } + +/* +* Decode a BER encoded EAC_Time +*/ +void EAC_Time::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + + if(obj.type_tag != this->tag) + throw BER_Decoding_Error("Tag mismatch when decoding"); + + if(obj.value.size() != 6) + { + throw Decoding_Error("EAC_Time decoding failed"); + } + + try + { + u32bit tmp_year = dec_two_digit(obj.value[0], obj.value[1]); + u32bit tmp_mon = dec_two_digit(obj.value[2], obj.value[3]); + u32bit tmp_day = dec_two_digit(obj.value[4], obj.value[5]); + year = tmp_year + 2000; + month = tmp_mon; + day = tmp_day; + } + catch (Invalid_Argument) + { + throw Decoding_Error("EAC_Time decoding failed"); + } + + } + +/* +* make the value an octet string for encoding +*/ +std::vector EAC_Time::encoded_eac_time() const + { + std::vector result; + result += enc_two_digit(year); + result += enc_two_digit(month); + result += enc_two_digit(day); + return result; + } + +} diff --git a/src/lib/cert/cvc/cvc_ado.cpp b/src/lib/cert/cvc/cvc_ado.cpp new file mode 100644 index 000000000..54bc9facd --- /dev/null +++ b/src/lib/cert/cvc/cvc_ado.cpp @@ -0,0 +1,127 @@ +/* +* CVC Certificate Constructor +* (C) 2007 FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +EAC1_1_ADO::EAC1_1_ADO(DataSource& in) + { + init(in); + do_decode(); + } + +EAC1_1_ADO::EAC1_1_ADO(const std::string& in) + { + DataSource_Stream stream(in, true); + init(stream); + do_decode(); + } + +void EAC1_1_ADO::force_decode() + { + std::vector inner_cert; + BER_Decoder(tbs_bits) + .start_cons(ASN1_Tag(33)) + .raw_bytes(inner_cert) + .end_cons() + .decode(m_car) + .verify_end(); + + std::vector req_bits = DER_Encoder() + .start_cons(ASN1_Tag(33), APPLICATION) + .raw_bytes(inner_cert) + .end_cons() + .get_contents_unlocked(); + + DataSource_Memory req_source(req_bits); + m_req = EAC1_1_Req(req_source); + sig_algo = m_req.sig_algo; + } + +std::vector EAC1_1_ADO::make_signed(PK_Signer& signer, + const std::vector& tbs_bits, + RandomNumberGenerator& rng) + { + const std::vector concat_sig = signer.sign_message(tbs_bits, rng); + + return DER_Encoder() + .start_cons(ASN1_Tag(7), APPLICATION) + .raw_bytes(tbs_bits) + .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION) + .end_cons() + .get_contents_unlocked(); + } + +ASN1_Car EAC1_1_ADO::get_car() const + { + return m_car; + } + +void EAC1_1_ADO::decode_info(DataSource& source, + std::vector & res_tbs_bits, + ECDSA_Signature & res_sig) + { + std::vector concat_sig; + std::vector cert_inner_bits; + ASN1_Car car; + + BER_Decoder(source) + .start_cons(ASN1_Tag(7)) + .start_cons(ASN1_Tag(33)) + .raw_bytes(cert_inner_bits) + .end_cons() + .decode(car) + .decode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION) + .end_cons(); + + std::vector enc_cert = DER_Encoder() + .start_cons(ASN1_Tag(33), APPLICATION) + .raw_bytes(cert_inner_bits) + .end_cons() + .get_contents_unlocked(); + + res_tbs_bits = enc_cert; + res_tbs_bits += DER_Encoder().encode(car).get_contents(); + res_sig = decode_concatenation(concat_sig); + } + +void EAC1_1_ADO::encode(Pipe& out, X509_Encoding encoding) const + { + if(encoding == PEM) + throw Invalid_Argument("EAC1_1_ADO::encode() cannot PEM encode an EAC object"); + + auto concat_sig = EAC1_1_obj::m_sig.get_concatenation(); + + out.write(DER_Encoder() + .start_cons(ASN1_Tag(7), APPLICATION) + .raw_bytes(tbs_bits) + .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION) + .end_cons() + .get_contents()); + } + +std::vector EAC1_1_ADO::tbs_data() const + { + return tbs_bits; + } + +bool EAC1_1_ADO::operator==(EAC1_1_ADO const& rhs) const + { + return (this->get_concat_sig() == rhs.get_concat_sig() + && this->tbs_data() == rhs.tbs_data() + && this->get_car() == rhs.get_car()); + } + +EAC1_1_Req EAC1_1_ADO::get_request() const + { + return m_req; + } + +} diff --git a/src/lib/cert/cvc/cvc_ado.h b/src/lib/cert/cvc/cvc_ado.h new file mode 100644 index 000000000..6f5b1d527 --- /dev/null +++ b/src/lib/cert/cvc/cvc_ado.h @@ -0,0 +1,98 @@ +/* +* EAC1_1 CVC ADO +* (C) 2008 Falko Strenzke +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAC_CVC_ADO_H__ +#define BOTAN_EAC_CVC_ADO_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents a TR03110 (EAC) v1.1 CVC ADO request +*/ + + // CRTP continuation from EAC1_1_obj +class BOTAN_DLL EAC1_1_ADO : public EAC1_1_obj + { + public: + friend class EAC1_1_obj; + + /** + * Construct a CVC ADO request from a DER encoded CVC ADO request file. + * @param str the path to the DER encoded file + */ + EAC1_1_ADO(const std::string& str); + + /** + * Construct a CVC ADO request from a data source + * @param source the data source + */ + EAC1_1_ADO(DataSource& source); + + /** + * Create a signed CVC ADO request from to be signed (TBS) data + * @param signer the signer used to sign the CVC ADO request + * @param tbs_bits the TBS data to sign + * @param rng a random number generator + */ + static std::vector make_signed( + PK_Signer& signer, + const std::vector& tbs_bits, + RandomNumberGenerator& rng); + + /** + * Get the CAR of this CVC ADO request + * @result the CAR of this CVC ADO request + */ + ASN1_Car get_car() const; + + /** + * Get the CVC request contained in this object. + * @result the CVC request inside this CVC ADO request + */ + EAC1_1_Req get_request() const; + + /** + * Encode this object into a pipe. Only DER is supported. + * @param out the pipe to encode this object into + * @param encoding the encoding type to use, must be DER + */ + void encode(Pipe& out, X509_Encoding encoding) const; + + bool operator==(EAC1_1_ADO const& rhs) const; + + /** + * Get the TBS data of this CVC ADO request. + * @result the TBS data + */ + std::vector tbs_data() const; + + virtual ~EAC1_1_ADO() {} + private: + ASN1_Car m_car; + EAC1_1_Req m_req; + + void force_decode(); + static void decode_info(DataSource& source, + std::vector & res_tbs_bits, + ECDSA_Signature & res_sig); + }; + +inline bool operator!=(EAC1_1_ADO const& lhs, EAC1_1_ADO const& rhs) + { + return (!(lhs == rhs)); + } + +} + +#endif + + diff --git a/src/lib/cert/cvc/cvc_cert.cpp b/src/lib/cert/cvc/cvc_cert.cpp new file mode 100644 index 000000000..3ab78b7d4 --- /dev/null +++ b/src/lib/cert/cvc/cvc_cert.cpp @@ -0,0 +1,135 @@ +/* + (C) 2007 FlexSecure GmbH + 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +ASN1_Car EAC1_1_CVC::get_car() const + { + return m_car; + } + +ASN1_Ced EAC1_1_CVC::get_ced() const + { + return m_ced; + } +ASN1_Cex EAC1_1_CVC::get_cex() const + { + return m_cex; + } +u32bit EAC1_1_CVC::get_chat_value() const + { + return m_chat_val; + } + +/* +* Decode the TBSCertificate data +*/ +void EAC1_1_CVC::force_decode() + { + std::vector enc_pk; + std::vector enc_chat_val; + size_t cpi; + BER_Decoder tbs_cert(tbs_bits); + tbs_cert.decode(cpi, ASN1_Tag(41), APPLICATION) + .decode(m_car) + .start_cons(ASN1_Tag(73)) + .raw_bytes(enc_pk) + .end_cons() + .decode(m_chr) + .start_cons(ASN1_Tag(76)) + .decode(m_chat_oid) + .decode(enc_chat_val, OCTET_STRING, ASN1_Tag(19), APPLICATION) + .end_cons() + .decode(m_ced) + .decode(m_cex) + .verify_end(); + + if(enc_chat_val.size() != 1) + throw Decoding_Error("CertificateHolderAuthorizationValue was not of length 1"); + + if(cpi != 0) + throw Decoding_Error("EAC1_1 certificate's cpi was not 0"); + + m_pk = decode_eac1_1_key(enc_pk, sig_algo); + + m_chat_val = enc_chat_val[0]; + + self_signed = (m_car.iso_8859() == m_chr.iso_8859()); + } + +/* +* CVC Certificate Constructor +*/ +EAC1_1_CVC::EAC1_1_CVC(DataSource& in) + { + init(in); + self_signed = false; + do_decode(); + } + +EAC1_1_CVC::EAC1_1_CVC(const std::string& in) + { + DataSource_Stream stream(in, true); + init(stream); + self_signed = false; + do_decode(); + } + +bool EAC1_1_CVC::operator==(EAC1_1_CVC const& rhs) const + { + return (tbs_data() == rhs.tbs_data() + && get_concat_sig() == rhs.get_concat_sig()); + } + +ECDSA_PublicKey* decode_eac1_1_key(const std::vector&, + AlgorithmIdentifier&) + { + throw Internal_Error("decode_eac1_1_key: Unimplemented"); + return 0; + } + +EAC1_1_CVC make_cvc_cert(PK_Signer& signer, + const std::vector& public_key, + ASN1_Car const& car, + ASN1_Chr const& chr, + byte holder_auth_templ, + ASN1_Ced ced, + ASN1_Cex cex, + RandomNumberGenerator& rng) + { + OID chat_oid(OIDS::lookup("CertificateHolderAuthorizationTemplate")); + std::vector enc_chat_val; + enc_chat_val.push_back(holder_auth_templ); + + std::vector enc_cpi; + enc_cpi.push_back(0x00); + std::vector tbs = DER_Encoder() + .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION) // cpi + .encode(car) + .raw_bytes(public_key) + .encode(chr) + .start_cons(ASN1_Tag(76), APPLICATION) + .encode(chat_oid) + .encode(enc_chat_val, OCTET_STRING, ASN1_Tag(19), APPLICATION) + .end_cons() + .encode(ced) + .encode(cex) + .get_contents_unlocked(); + + std::vector signed_cert = + EAC1_1_CVC::make_signed(signer, + EAC1_1_CVC::build_cert_body(tbs), + rng); + + DataSource_Memory source(signed_cert); + return EAC1_1_CVC(source); + } + +} diff --git a/src/lib/cert/cvc/cvc_cert.h b/src/lib/cert/cvc/cvc_cert.h new file mode 100644 index 000000000..7c084379f --- /dev/null +++ b/src/lib/cert/cvc/cvc_cert.h @@ -0,0 +1,116 @@ +/* +* EAC1_1 CVC +* (C) 2008 Falko Strenzke +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CVC_EAC_H__ +#define BOTAN_CVC_EAC_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents TR03110 (EAC) v1.1 CV Certificates +*/ +class BOTAN_DLL EAC1_1_CVC : public EAC1_1_gen_CVC//Signed_Object + { + public: + friend class EAC1_1_obj; + + /** + * Get the CAR of the certificate. + * @result the CAR of the certificate + */ + ASN1_Car get_car() const; + + /** + * Get the CED of this certificate. + * @result the CED this certificate + */ + ASN1_Ced get_ced() const; + + /** + * Get the CEX of this certificate. + * @result the CEX this certificate + */ + ASN1_Cex get_cex() const; + + /** + * Get the CHAT value. + * @result the CHAT value + */ + u32bit get_chat_value() const; + + bool operator==(const EAC1_1_CVC&) const; + + /** + * Construct a CVC from a data source + * @param source the data source + */ + EAC1_1_CVC(DataSource& source); + + /** + * Construct a CVC from a file + * @param str the path to the certificate file + */ + EAC1_1_CVC(const std::string& str); + + virtual ~EAC1_1_CVC() {} + private: + void force_decode(); + EAC1_1_CVC() {} + + ASN1_Car m_car; + ASN1_Ced m_ced; + ASN1_Cex m_cex; + byte m_chat_val; + OID m_chat_oid; + }; + +/* +* Comparison +*/ +inline bool operator!=(EAC1_1_CVC const& lhs, EAC1_1_CVC const& rhs) + { + return !(lhs == rhs); + } + +/** +* Create an arbitrary EAC 1.1 CVC. +* The desired key encoding must be set within the key (if applicable). +* @param signer the signer used to sign the certificate +* @param public_key the DER encoded public key to appear in +* the certificate +* @param car the CAR of the certificate +* @param chr the CHR of the certificate +* @param holder_auth_templ the holder authorization value byte to +* appear in the CHAT of the certificate +* @param ced the CED to appear in the certificate +* @param cex the CEX to appear in the certificate +* @param rng a random number generator +*/ +EAC1_1_CVC BOTAN_DLL make_cvc_cert(PK_Signer& signer, + const std::vector& public_key, + ASN1_Car const& car, + ASN1_Chr const& chr, + byte holder_auth_templ, + ASN1_Ced ced, + ASN1_Cex cex, + RandomNumberGenerator& rng); + +/** +* Decode an EAC encoding ECDSA key +*/ +BOTAN_DLL ECDSA_PublicKey* decode_eac1_1_key(const std::vector& enc_key, + AlgorithmIdentifier& sig_algo); + +} + +#endif + diff --git a/src/lib/cert/cvc/cvc_gen_cert.h b/src/lib/cert/cvc/cvc_gen_cert.h new file mode 100644 index 000000000..7fa4eba29 --- /dev/null +++ b/src/lib/cert/cvc/cvc_gen_cert.h @@ -0,0 +1,180 @@ +/* +* EAC1_1 general CVC +* (C) 2008 Falko Strenzke +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAC_CVC_GEN_CERT_H__ +#define BOTAN_EAC_CVC_GEN_CERT_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents TR03110 (EAC) v1.1 generalized CV Certificates +*/ +template +class EAC1_1_gen_CVC : public EAC1_1_obj // CRTP continuation from EAC1_1_obj + { + friend class EAC1_1_obj; + + public: + + /** + * Get this certificates public key. + * @result this certificates public key + */ + Public_Key* subject_public_key() const; + + /** + * Find out whether this object is self signed. + * @result true if this object is self signed + */ + bool is_self_signed() const; + + /** + * Get the CHR of the certificate. + * @result the CHR of the certificate + */ + ASN1_Chr get_chr() const; + + /** + * Put the DER encoded version of this object into a pipe. PEM + * is not supported. + * @param out the pipe to push the DER encoded version into + * @param encoding the encoding to use. Must be DER. + */ + void encode(Pipe& out, X509_Encoding encoding) const; + + /** + * Get the to-be-signed (TBS) data of this object. + * @result the TBS data of this object + */ + std::vector tbs_data() const; + + /** + * Build the DER encoded certifcate body of an object + * @param tbs the data to be signed + * @result the correctly encoded body of the object + */ + static std::vector build_cert_body(const std::vector& tbs); + + /** + * Create a signed generalized CVC object. + * @param signer the signer used to sign this object + * @param tbs_bits the body the generalized CVC object to be signed + * @param rng a random number generator + * @result the DER encoded signed generalized CVC object + */ + static std::vector make_signed( + PK_Signer& signer, + const std::vector& tbs_bits, + RandomNumberGenerator& rng); + + EAC1_1_gen_CVC() { m_pk = 0; } + + virtual ~EAC1_1_gen_CVC() + { delete m_pk; } + + protected: + ECDSA_PublicKey* m_pk; + ASN1_Chr m_chr; + bool self_signed; + + static void decode_info(DataSource& source, + std::vector & res_tbs_bits, + ECDSA_Signature & res_sig); + + }; + +template ASN1_Chr EAC1_1_gen_CVC::get_chr() const + { + return m_chr; + } + +template bool EAC1_1_gen_CVC::is_self_signed() const + { + return self_signed; + } + +template +std::vector EAC1_1_gen_CVC::make_signed( + PK_Signer& signer, + const std::vector& tbs_bits, + RandomNumberGenerator& rng) // static + { + const auto concat_sig = signer.sign_message(tbs_bits, rng); + + return DER_Encoder() + .start_cons(ASN1_Tag(33), APPLICATION) + .raw_bytes(tbs_bits) + .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION) + .end_cons() + .get_contents_unlocked(); + } + +template +Public_Key* EAC1_1_gen_CVC::subject_public_key() const + { + return new ECDSA_PublicKey(*m_pk); + } + +template std::vector EAC1_1_gen_CVC::build_cert_body(const std::vector& tbs) + { + return DER_Encoder() + .start_cons(ASN1_Tag(78), APPLICATION) + .raw_bytes(tbs) + .end_cons().get_contents_unlocked(); + } + +template std::vector EAC1_1_gen_CVC::tbs_data() const + { + return build_cert_body(EAC1_1_obj::tbs_bits); + } + +template void EAC1_1_gen_CVC::encode(Pipe& out, X509_Encoding encoding) const + { + std::vector concat_sig(EAC1_1_obj::m_sig.get_concatenation()); + std::vector der = DER_Encoder() + .start_cons(ASN1_Tag(33), APPLICATION) + .start_cons(ASN1_Tag(78), APPLICATION) + .raw_bytes(EAC1_1_obj::tbs_bits) + .end_cons() + .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION) + .end_cons() + .get_contents_unlocked(); + + if (encoding == PEM) + throw Invalid_Argument("EAC1_1_gen_CVC::encode() cannot PEM encode an EAC object"); + else + out.write(der); + } + +template +void EAC1_1_gen_CVC::decode_info( + DataSource& source, + std::vector & res_tbs_bits, + ECDSA_Signature & res_sig) + { + std::vector concat_sig; + BER_Decoder(source) + .start_cons(ASN1_Tag(33)) + .start_cons(ASN1_Tag(78)) + .raw_bytes(res_tbs_bits) + .end_cons() + .decode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION) + .end_cons(); + res_sig = decode_concatenation(concat_sig); + } + +} + +#endif + + diff --git a/src/lib/cert/cvc/cvc_req.cpp b/src/lib/cert/cvc/cvc_req.cpp new file mode 100644 index 000000000..6c013f755 --- /dev/null +++ b/src/lib/cert/cvc/cvc_req.cpp @@ -0,0 +1,53 @@ +/* + (C) 2007 FlexSecure GmbH + 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +bool EAC1_1_Req::operator==(EAC1_1_Req const& rhs) const + { + return (this->tbs_data() == rhs.tbs_data() && + this->get_concat_sig() == rhs.get_concat_sig()); + } + +void EAC1_1_Req::force_decode() + { + std::vector enc_pk; + BER_Decoder tbs_cert(tbs_bits); + size_t cpi; + tbs_cert.decode(cpi, ASN1_Tag(41), APPLICATION) + .start_cons(ASN1_Tag(73)) + .raw_bytes(enc_pk) + .end_cons() + .decode(m_chr) + .verify_end(); + + if(cpi != 0) + throw Decoding_Error("EAC1_1 requests cpi was not 0"); + + m_pk = decode_eac1_1_key(enc_pk, sig_algo); + } + +EAC1_1_Req::EAC1_1_Req(DataSource& in) + { + init(in); + self_signed = true; + do_decode(); + } + +EAC1_1_Req::EAC1_1_Req(const std::string& in) + { + DataSource_Stream stream(in, true); + init(stream); + self_signed = true; + do_decode(); + } + +} diff --git a/src/lib/cert/cvc/cvc_req.h b/src/lib/cert/cvc/cvc_req.h new file mode 100644 index 000000000..ac4e22453 --- /dev/null +++ b/src/lib/cert/cvc/cvc_req.h @@ -0,0 +1,59 @@ +/* +* EAC1_1 CVC Request +* (C) 2008 Falko Strenzke +* 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAC_CVC_REQ_H__ +#define BOTAN_EAC_CVC_REQ_H__ + +#include + +namespace Botan { + +/** +* This class represents TR03110 v1.1 EAC CV Certificate Requests. +*/ +class BOTAN_DLL EAC1_1_Req : public EAC1_1_gen_CVC + { + public: + friend class EAC1_1_ADO; + friend class EAC1_1_obj; + + /** + * Compare for equality with other + * @param other compare for equality with this object + */ + bool operator==(const EAC1_1_Req& other) const; + + /** + * Construct a CVC request from a data source. + * @param source the data source + */ + EAC1_1_Req(DataSource& source); + + /** + * Construct a CVC request from a DER encoded CVC request file. + * @param str the path to the DER encoded file + */ + EAC1_1_Req(const std::string& str); + + virtual ~EAC1_1_Req(){} + private: + void force_decode(); + EAC1_1_Req() {} + }; + +/* +* Comparison Operator +*/ +inline bool operator!=(EAC1_1_Req const& lhs, EAC1_1_Req const& rhs) + { + return !(lhs == rhs); + } + +} + +#endif diff --git a/src/lib/cert/cvc/cvc_self.cpp b/src/lib/cert/cvc/cvc_self.cpp new file mode 100644 index 000000000..46e4960e1 --- /dev/null +++ b/src/lib/cert/cvc/cvc_self.cpp @@ -0,0 +1,340 @@ +/* + (C) 2007 FlexSecure GmbH + 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* cvc CHAT values +*/ +enum CHAT_values{ + CVCA = 0xC0, + DVCA_domestic = 0x80, + DVCA_foreign = 0x40, + IS = 0x00, + + IRIS = 0x02, + FINGERPRINT = 0x01 +}; + +void encode_eac_bigint(DER_Encoder& der, const BigInt& x, ASN1_Tag tag) + { + der.encode(BigInt::encode_1363(x, x.bytes()), OCTET_STRING, tag); + } + +std::vector eac_1_1_encoding(const EC_PublicKey* key, + const OID& sig_algo) + { + if(key->domain_format() == EC_DOMPAR_ENC_OID) + throw Encoding_Error("CVC encoder: cannot encode parameters by OID"); + + const EC_Group& domain = key->domain(); + + // This is why we can't have nice things + + DER_Encoder enc; + enc.start_cons(ASN1_Tag(73), APPLICATION) + .encode(sig_algo); + + if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT) + { + encode_eac_bigint(enc, domain.get_curve().get_p(), ASN1_Tag(1)); + encode_eac_bigint(enc, domain.get_curve().get_a(), ASN1_Tag(2)); + encode_eac_bigint(enc, domain.get_curve().get_b(), ASN1_Tag(3)); + + enc.encode(EC2OSP(domain.get_base_point(), PointGFp::UNCOMPRESSED), + OCTET_STRING, ASN1_Tag(4)); + + encode_eac_bigint(enc, domain.get_order(), ASN1_Tag(4)); + } + + enc.encode(EC2OSP(key->public_point(), PointGFp::UNCOMPRESSED), + OCTET_STRING, ASN1_Tag(6)); + + if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT) + encode_eac_bigint(enc, domain.get_cofactor(), ASN1_Tag(7)); + + enc.end_cons(); + + return enc.get_contents_unlocked(); + } + +std::string padding_and_hash_from_oid(OID const& oid) + { + std::string padding_and_hash = OIDS::lookup(oid); // use the hash + + if(padding_and_hash.substr(0,6) != "ECDSA/") + throw Invalid_State("CVC: Can only use ECDSA, not " + padding_and_hash); + + padding_and_hash.erase(0, padding_and_hash.find("/") + 1); + return padding_and_hash; + } + +} + +namespace CVC_EAC { + +EAC1_1_CVC create_self_signed_cert(Private_Key const& key, + EAC1_1_CVC_Options const& opt, + RandomNumberGenerator& rng) + { + // NOTE: we ignore the value of opt.chr + + const ECDSA_PrivateKey* priv_key = dynamic_cast(&key); + + if(priv_key == 0) + throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); + + ASN1_Chr chr(opt.car.value()); + + AlgorithmIdentifier sig_algo; + std::string padding_and_hash("EMSA1_BSI(" + opt.hash_alg + ")"); + sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash); + sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM); + + PK_Signer signer(*priv_key, padding_and_hash); + + std::vector enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid); + + return make_cvc_cert(signer, + enc_public_key, + opt.car, chr, + opt.holder_auth_templ, + opt.ced, opt.cex, rng); + } + +EAC1_1_Req create_cvc_req(Private_Key const& key, + ASN1_Chr const& chr, + std::string const& hash_alg, + RandomNumberGenerator& rng) + { + + ECDSA_PrivateKey const* priv_key = dynamic_cast(&key); + if (priv_key == 0) + { + throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); + } + AlgorithmIdentifier sig_algo; + std::string padding_and_hash("EMSA1_BSI(" + hash_alg + ")"); + sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash); + sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM); + + PK_Signer signer(*priv_key, padding_and_hash); + + std::vector enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid); + + std::vector enc_cpi; + enc_cpi.push_back(0x00); + std::vector tbs = DER_Encoder() + .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION) + .raw_bytes(enc_public_key) + .encode(chr) + .get_contents_unlocked(); + + std::vector signed_cert = + EAC1_1_gen_CVC::make_signed(signer, + EAC1_1_gen_CVC::build_cert_body(tbs), + rng); + + DataSource_Memory source(signed_cert); + return EAC1_1_Req(source); + } + +EAC1_1_ADO create_ado_req(Private_Key const& key, + EAC1_1_Req const& req, + ASN1_Car const& car, + RandomNumberGenerator& rng) + { + + ECDSA_PrivateKey const* priv_key = dynamic_cast(&key); + if (priv_key == 0) + { + throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); + } + + std::string padding_and_hash = padding_and_hash_from_oid(req.signature_algorithm().oid); + PK_Signer signer(*priv_key, padding_and_hash); + std::vector tbs_bits = req.BER_encode(); + tbs_bits += DER_Encoder().encode(car).get_contents(); + + std::vector signed_cert = + EAC1_1_ADO::make_signed(signer, tbs_bits, rng); + + DataSource_Memory source(signed_cert); + return EAC1_1_ADO(source); + } + +} // namespace CVC_EAC +namespace DE_EAC +{ + +EAC1_1_CVC create_cvca(Private_Key const& key, + std::string const& hash, + ASN1_Car const& car, bool iris, bool fingerpr, + u32bit cvca_validity_months, + RandomNumberGenerator& rng) + { + ECDSA_PrivateKey const* priv_key = dynamic_cast(&key); + if (priv_key == 0) + { + throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); + } + EAC1_1_CVC_Options opts; + opts.car = car; + + opts.ced = ASN1_Ced(std::chrono::system_clock::now()); + opts.cex = ASN1_Cex(opts.ced); + opts.cex.add_months(cvca_validity_months); + opts.holder_auth_templ = (CVCA | (iris * IRIS) | (fingerpr * FINGERPRINT)); + opts.hash_alg = hash; + return CVC_EAC::create_self_signed_cert(*priv_key, opts, rng); + } + + + +EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer, + Private_Key const& key, + EAC1_1_CVC const& signee, + RandomNumberGenerator& rng) + { + const ECDSA_PrivateKey* priv_key = dynamic_cast(&key); + + if (priv_key == 0) + throw Invalid_Argument("link_cvca(): unsupported key type"); + + ASN1_Ced ced(std::chrono::system_clock::now()); + ASN1_Cex cex(signee.get_cex()); + if (*static_cast(&ced) > *static_cast(&cex)) + { + std::string detail("link_cvca(): validity periods of provided certificates don't overlap: currend time = ced = "); + detail += ced.as_string(); + detail += ", signee.cex = "; + detail += cex.as_string(); + throw Invalid_Argument(detail); + } + if (signer.signature_algorithm() != signee.signature_algorithm()) + { + throw Invalid_Argument("link_cvca(): signature algorithms of signer and signee don't match"); + } + AlgorithmIdentifier sig_algo = signer.signature_algorithm(); + std::string padding_and_hash = padding_and_hash_from_oid(sig_algo.oid); + PK_Signer pk_signer(*priv_key, padding_and_hash); + std::unique_ptr pk(signee.subject_public_key()); + ECDSA_PublicKey* subj_pk = dynamic_cast(pk.get()); + subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_EXPLICIT); + + std::vector enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid); + + return make_cvc_cert(pk_signer, enc_public_key, + signer.get_car(), + signee.get_chr(), + signer.get_chat_value(), + ced, cex, + rng); + } + +EAC1_1_CVC sign_request(EAC1_1_CVC const& signer_cert, + Private_Key const& key, + EAC1_1_Req const& signee, + u32bit seqnr, + u32bit seqnr_len, + bool domestic, + u32bit dvca_validity_months, + u32bit ca_is_validity_months, + RandomNumberGenerator& rng) + { + ECDSA_PrivateKey const* priv_key = dynamic_cast(&key); + if (priv_key == 0) + { + throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); + } + std::string chr_str = signee.get_chr().value(); + + std::string seqnr_string = std::to_string(seqnr); + + while(seqnr_string.size() < seqnr_len) + seqnr_string = '0' + seqnr_string; + + chr_str += seqnr_string; + ASN1_Chr chr(chr_str); + std::string padding_and_hash = padding_and_hash_from_oid(signee.signature_algorithm().oid); + PK_Signer pk_signer(*priv_key, padding_and_hash); + std::unique_ptr pk(signee.subject_public_key()); + ECDSA_PublicKey* subj_pk = dynamic_cast(pk.get()); + std::unique_ptr signer_pk(signer_cert.subject_public_key()); + + // for the case that the domain parameters are not set... + // (we use those from the signer because they must fit) + //subj_pk->set_domain_parameters(priv_key->domain_parameters()); + + subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA); + + AlgorithmIdentifier sig_algo(signer_cert.signature_algorithm()); + + ASN1_Ced ced(std::chrono::system_clock::now()); + + u32bit chat_val; + u32bit chat_low = signer_cert.get_chat_value() & 0x3; // take the chat rights from signer + ASN1_Cex cex(ced); + if ((signer_cert.get_chat_value() & CVCA) == CVCA) + { + // we sign a dvca + cex.add_months(dvca_validity_months); + if (domestic) + chat_val = DVCA_domestic | chat_low; + else + chat_val = DVCA_foreign | chat_low; + } + else if ((signer_cert.get_chat_value() & DVCA_domestic) == DVCA_domestic || + (signer_cert.get_chat_value() & DVCA_foreign) == DVCA_foreign) + { + cex.add_months(ca_is_validity_months); + chat_val = IS | chat_low; + } + else + { + throw Invalid_Argument("sign_request(): encountered illegal value for CHAT"); + // (IS cannot sign certificates) + } + + std::vector enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid); + + return make_cvc_cert(pk_signer, enc_public_key, + ASN1_Car(signer_cert.get_chr().iso_8859()), + chr, + chat_val, + ced, + cex, + rng); + } + +EAC1_1_Req create_cvc_req(Private_Key const& prkey, + ASN1_Chr const& chr, + std::string const& hash_alg, + RandomNumberGenerator& rng) + { + ECDSA_PrivateKey const* priv_key = dynamic_cast(&prkey); + if (priv_key == 0) + { + throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); + } + ECDSA_PrivateKey key(*priv_key); + key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA); + return CVC_EAC::create_cvc_req(key, chr, hash_alg, rng); + } + +} // namespace DE_EAC + +} diff --git a/src/lib/cert/cvc/cvc_self.h b/src/lib/cert/cvc/cvc_self.h new file mode 100644 index 000000000..1e6bbe49a --- /dev/null +++ b/src/lib/cert/cvc/cvc_self.h @@ -0,0 +1,170 @@ +/* +* CVC Self-Signed Certificate +* (C) 2007 FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CVC_EAC_SELF_H__ +#define BOTAN_CVC_EAC_SELF_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents a set of options used for the creation of CVC certificates +*/ +class BOTAN_DLL EAC1_1_CVC_Options + { + public: + + ASN1_Car car; + ASN1_Chr chr; + byte holder_auth_templ; + ASN1_Ced ced; + ASN1_Cex cex; + std::string hash_alg; + }; + +/** +* This namespace represents general EAC 1.1 convenience functions. +*/ +namespace CVC_EAC { + +/** +* Create a selfsigned CVCA +* @param rng the rng to use +* @param key the ECDSA private key to be used to sign the certificate +* @param opts used to set several parameters. Necessary are: +* car, holder_auth_templ, hash_alg, ced, cex and hash_alg +* @result the self signed certificate +*/ + +EAC1_1_CVC BOTAN_DLL create_self_signed_cert(Private_Key const& key, + EAC1_1_CVC_Options const& opts, + RandomNumberGenerator& rng); +/** +* Create a CVC request. The key encoding will be according to the provided private key. +* @param priv_key the private key associated with the requesting entity +* @param chr the chr to appear in the certificate (to be provided without +* sequence number) +* @param hash_alg the string defining the hash algorithm to be used for the creation +* of the signature +* @param rng the rng to use +* @result the new request +*/ +EAC1_1_Req BOTAN_DLL create_cvc_req(Private_Key const& priv_key, + ASN1_Chr const& chr, + std::string const& hash_alg, + RandomNumberGenerator& rng); + +/** +* Create an ADO from a request object. +* @param priv_key the private key used to sign the ADO +* @param req the request forming the body of the ADO +* @param car the CAR forming the body of the ADO, i.e. the +* CHR of the entity associated with the provided private key +* @param rng the rng to use +*/ +EAC1_1_ADO BOTAN_DLL create_ado_req(Private_Key const& priv_key, + EAC1_1_Req const& req, + ASN1_Car const& car, + RandomNumberGenerator& rng); +} +/** +* This namespace represents EAC 1.1 CVC convenience functions +* following the specific german requirements. +*/ + +namespace DE_EAC { + +/** +* Create a CVCA certificate. +* @param priv_key the private key associated with the CVCA certificate +* to be created +* @param hash the string identifying the hash algorithm to be used +* for signing the certificate to be created +* @param car the CAR of the certificate to be created +* @param iris indicates whether the entity associated with the certificate +* shall be entitled to read the biometrical iris image +* @param fingerpr indicates whether the entity associated with the certificate +* shall be entitled to read the biometrical fingerprint image +* @param cvca_validity_months length of time in months this will be valid +* @param rng a random number generator +* @result the CVCA certificate created +*/ +EAC1_1_CVC BOTAN_DLL create_cvca(Private_Key const& priv_key, + std::string const& hash, + ASN1_Car const& car, + bool iris, + bool fingerpr, + u32bit cvca_validity_months, + RandomNumberGenerator& rng); + +/** +* Create a link certificate between two CVCA certificates. The key +* encoding will be implicitCA. +* @param signer the cvca certificate associated with the signing +* entity +* @param priv_key the private key associated with the signer +* @param to_be_signed the certificate which whose CAR/CHR will be +* the holder of the link certificate +* @param rng a random number generator +*/ +EAC1_1_CVC BOTAN_DLL link_cvca(EAC1_1_CVC const& signer, + Private_Key const& priv_key, + EAC1_1_CVC const& to_be_signed, + RandomNumberGenerator& rng); + +/** +* Create a CVC request. The key encoding will be implicitCA. +* @param priv_key the private key associated with the requesting entity +* @param chr the chr to appear in the certificate (to be provided without +* sequence number) +* @param hash_alg the string defining the hash algorithm to be used for the creation +* of the signature +* @param rng a random number generator +* @result the new request +*/ +EAC1_1_Req BOTAN_DLL create_cvc_req(Private_Key const& priv_key, + ASN1_Chr const& chr, + std::string const& hash_alg, + RandomNumberGenerator& rng); + +/** +* Sign a CVC request. +* @param signer_cert the certificate of the signing entity +* @param priv_key the private key of the signing entity +* @param req the request to be signed +* @param seqnr the sequence number of the certificate to be created +* @param seqnr_len the number of digits the sequence number will be +* encoded in +* @param domestic indicates whether to sign a domestic or a foreign +* certificate: set to true for domestic +* @param dvca_validity_months validity period in months +* @param ca_is_validity_months validity period in months +* @param rng a random number generator +* @result the new certificate +* +**/ +EAC1_1_CVC BOTAN_DLL sign_request(EAC1_1_CVC const& signer_cert, + Private_Key const& priv_key, + EAC1_1_Req const& req, + u32bit seqnr, + u32bit seqnr_len, + bool domestic, + u32bit dvca_validity_months, + u32bit ca_is_validity_months, + RandomNumberGenerator& rng); +} + +} + +#endif diff --git a/src/lib/cert/cvc/eac_asn_obj.h b/src/lib/cert/cvc/eac_asn_obj.h new file mode 100644 index 000000000..ab8536e45 --- /dev/null +++ b/src/lib/cert/cvc/eac_asn_obj.h @@ -0,0 +1,238 @@ +/* +* EAC ASN.1 Objects +* (C) 2007-2008 FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAC_ASN1_OBJ_H__ +#define BOTAN_EAC_ASN1_OBJ_H__ + +#include + +namespace Botan { + +/** +* This class represents CVC EAC Time objects. +* It only models year, month and day. Only limited sanity checks of +* the inputted date value are performed. +*/ +class BOTAN_DLL EAC_Time : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + /** + * Get a this objects value as a string. + * @return date string + */ + std::string as_string() const; + + /** + * Get a this objects value as a readable formatted string. + * @return date string + */ + std::string readable_string() const; + + /** + * Find out whether this object's values have been set. + * @return true if this object's internal values are set + */ + bool time_is_set() const; + + /** + * Compare this to another EAC_Time object. + * @return -1 if this object's date is earlier than + * other, +1 in the opposite case, and 0 if both dates are + * equal. + */ + s32bit cmp(const EAC_Time& other) const; + + /** + * Set this' value by a string value. + * @param str a string in the format "yyyy mm dd", + * e.g. "2007 08 01" + */ + void set_to(const std::string& str); + + /** + * Add the specified number of years to this. + * @param years the number of years to add + */ + void add_years(u32bit years); + + /** + * Add the specified number of months to this. + * @param months the number of months to add + */ + void add_months(u32bit months); + + /** + * Get the year value of this objects. + * @return year value + */ + u32bit get_year() const { return year; } + + /** + * Get the month value of this objects. + * @return month value + */ + u32bit get_month() const { return month; } + + /** + * Get the day value of this objects. + * @return day value + */ + u32bit get_day() const { return day; } + + EAC_Time(const std::chrono::system_clock::time_point& time, + ASN1_Tag tag = ASN1_Tag(0)); + + EAC_Time(const std::string& yyyy_mm_dd, + ASN1_Tag tag = ASN1_Tag(0)); + + EAC_Time(u32bit year, u32bit month, u32bit day, + ASN1_Tag tag = ASN1_Tag(0)); + + virtual ~EAC_Time() {} + private: + std::vector encoded_eac_time() const; + bool passes_sanity_check() const; + u32bit year, month, day; + ASN1_Tag tag; + }; + +/** +* This class represents CVC CEDs. Only limited sanity checks of +* the inputted date value are performed. +*/ +class BOTAN_DLL ASN1_Ced : public EAC_Time + { + public: + /** + * Construct a CED from a string value. + * @param str a string in the format "yyyy mm dd", + * e.g. "2007 08 01" + */ + ASN1_Ced(const std::string& str = "") : + EAC_Time(str, ASN1_Tag(37)) {} + + /** + * Construct a CED from a time point + */ + ASN1_Ced(const std::chrono::system_clock::time_point& time) : + EAC_Time(time, ASN1_Tag(37)) {} + + /** + * Copy constructor (for general EAC_Time objects). + * @param other the object to copy from + */ + ASN1_Ced(const EAC_Time& other) : + EAC_Time(other.get_year(), other.get_month(), other.get_day(), + ASN1_Tag(37)) + {} + }; + +/** +* This class represents CVC CEXs. Only limited sanity checks of +* the inputted date value are performed. +*/ +class BOTAN_DLL ASN1_Cex : public EAC_Time + { + public: + /** + * Construct a CEX from a string value. + * @param str a string in the format "yyyy mm dd", + * e.g. "2007 08 01" + */ + ASN1_Cex(const std::string& str = "") : + EAC_Time(str, ASN1_Tag(36)) {} + + ASN1_Cex(const std::chrono::system_clock::time_point& time) : + EAC_Time(time, ASN1_Tag(36)) {} + + ASN1_Cex(const EAC_Time& other) : + EAC_Time(other.get_year(), other.get_month(), other.get_day(), + ASN1_Tag(36)) + {} + }; + +/** +* Base class for car/chr of cv certificates. +*/ +class BOTAN_DLL ASN1_EAC_String: public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + /** + * Get this objects string value. + * @return string value + */ + std::string value() const; + + /** + * Get this objects string value. + * @return string value in iso8859 encoding + */ + std::string iso_8859() const; + + ASN1_Tag tagging() const; + ASN1_EAC_String(const std::string& str, ASN1_Tag the_tag); + + virtual ~ASN1_EAC_String() {} + protected: + bool sanity_check() const; + private: + std::string iso_8859_str; + ASN1_Tag tag; + }; + +/** +* This class represents CARs of CVCs. (String tagged with 2) +*/ +class BOTAN_DLL ASN1_Car : public ASN1_EAC_String + { + public: + /** + * Create a CAR with the specified content. + * @param str the CAR value + */ + ASN1_Car(std::string const& str = ""); + }; + +/** +* This class represents CHRs of CVCs (tag 32) +*/ +class BOTAN_DLL ASN1_Chr : public ASN1_EAC_String + { + public: + /** + * Create a CHR with the specified content. + * @param str the CHR value + */ + ASN1_Chr(std::string const& str = ""); + }; + +/* +* Comparison Operations +*/ +bool BOTAN_DLL operator==(const EAC_Time&, const EAC_Time&); +bool BOTAN_DLL operator!=(const EAC_Time&, const EAC_Time&); +bool BOTAN_DLL operator<=(const EAC_Time&, const EAC_Time&); +bool BOTAN_DLL operator>=(const EAC_Time&, const EAC_Time&); +bool BOTAN_DLL operator>(const EAC_Time&, const EAC_Time&); +bool BOTAN_DLL operator<(const EAC_Time&, const EAC_Time&); + +bool BOTAN_DLL operator==(const ASN1_EAC_String&, const ASN1_EAC_String&); +inline bool operator!=(const ASN1_EAC_String& lhs, const ASN1_EAC_String& rhs) + { + return !(lhs == rhs); + } + +} + +#endif diff --git a/src/lib/cert/cvc/eac_obj.h b/src/lib/cert/cvc/eac_obj.h new file mode 100644 index 000000000..42274446c --- /dev/null +++ b/src/lib/cert/cvc/eac_obj.h @@ -0,0 +1,55 @@ +/* +* EAC1_1 objects +* (C) 2008 Falko Strenzke +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAC_OBJ_H__ +#define BOTAN_EAC_OBJ_H__ + +#include +#include + +namespace Botan { + +/** +* TR03110 v1.1 EAC CV Certificate +*/ +template // CRTP is used enable the call sequence: +class EAC1_1_obj : public EAC_Signed_Object + { + public: + /** + * Return the signature as a concatenation of the encoded parts. + * @result the concatenated signature + */ + std::vector get_concat_sig() const + { return m_sig.get_concatenation(); } + + bool check_signature(class Public_Key& key) const + { + return EAC_Signed_Object::check_signature(key, m_sig.DER_encode()); + } + + protected: + ECDSA_Signature m_sig; + + void init(DataSource& in) + { + try + { + Derived::decode_info(in, tbs_bits, m_sig); + } + catch(Decoding_Error) + { + throw Decoding_Error(PEM_label_pref + " decoding failed"); + } + } + + virtual ~EAC1_1_obj(){} + }; + +} + +#endif diff --git a/src/lib/cert/cvc/ecdsa_sig.cpp b/src/lib/cert/cvc/ecdsa_sig.cpp new file mode 100644 index 000000000..690244d50 --- /dev/null +++ b/src/lib/cert/cvc/ecdsa_sig.cpp @@ -0,0 +1,59 @@ +/* +* ECDSA Signature +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +ECDSA_Signature::ECDSA_Signature(const std::vector& ber) + { + BER_Decoder(ber) + .start_cons(SEQUENCE) + .decode(m_r) + .decode(m_s) + .end_cons() + .verify_end(); + } + +std::vector ECDSA_Signature::DER_encode() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(get_r()) + .encode(get_s()) + .end_cons() + .get_contents_unlocked(); + } + +std::vector ECDSA_Signature::get_concatenation() const + { + // use the larger + const size_t enc_len = m_r > m_s ? m_r.bytes() : m_s.bytes(); + + const auto sv_r = BigInt::encode_1363(m_r, enc_len); + const auto sv_s = BigInt::encode_1363(m_s, enc_len); + + secure_vector result(sv_r); + result += sv_s; + return unlock(result); + } + +ECDSA_Signature decode_concatenation(const std::vector& concat) + { + if(concat.size() % 2 != 0) + throw Invalid_Argument("Erroneous length of signature"); + + const size_t rs_len = concat.size() / 2; + + BigInt r = BigInt::decode(&concat[0], rs_len); + BigInt s = BigInt::decode(&concat[rs_len], rs_len); + + return ECDSA_Signature(r, s); + } + +} diff --git a/src/lib/cert/cvc/ecdsa_sig.h b/src/lib/cert/cvc/ecdsa_sig.h new file mode 100644 index 000000000..1c3b506cb --- /dev/null +++ b/src/lib/cert/cvc/ecdsa_sig.h @@ -0,0 +1,61 @@ +/* +* ECDSA Signature +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECDSA_SIGNATURE_H__ +#define BOTAN_ECDSA_SIGNATURE_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Class representing an ECDSA signature +*/ +class BOTAN_DLL ECDSA_Signature + { + public: + friend class ECDSA_Signature_Decoder; + + ECDSA_Signature() {} + ECDSA_Signature(const BigInt& r, const BigInt& s) : + m_r(r), m_s(s) {} + + ECDSA_Signature(const std::vector& ber); + + const BigInt& get_r() const { return m_r; } + const BigInt& get_s() const { return m_s; } + + /** + * return the r||s + */ + std::vector get_concatenation() const; + + std::vector DER_encode() const; + + bool operator==(const ECDSA_Signature& other) const + { + return (get_r() == other.get_r() && get_s() == other.get_s()); + } + + private: + BigInt m_r; + BigInt m_s; + }; + +inline bool operator!=(const ECDSA_Signature& lhs, const ECDSA_Signature& rhs) + { + return !(lhs == rhs); + } + +ECDSA_Signature decode_concatenation(const std::vector& concatenation); + +} + +#endif diff --git a/src/lib/cert/cvc/info.txt b/src/lib/cert/cvc/info.txt new file mode 100644 index 000000000..1d8e54dc4 --- /dev/null +++ b/src/lib/cert/cvc/info.txt @@ -0,0 +1,36 @@ +define CARD_VERIFIABLE_CERTIFICATES 20131128 +load_on request + + +cvc_ado.h +cvc_cert.h +cvc_gen_cert.h +cvc_req.h +cvc_self.h +eac_asn_obj.h +eac_obj.h +ecdsa_sig.h +signed_obj.h + + + +asn1_eac_str.cpp +asn1_eac_tm.cpp +ecdsa_sig.cpp +cvc_ado.cpp +cvc_cert.cpp +cvc_req.cpp +cvc_self.cpp +signed_obj.cpp + + + +asn1 +bigint +ecdsa +filters +libstate +oid_lookup +pem +pubkey + diff --git a/src/lib/cert/cvc/signed_obj.cpp b/src/lib/cert/cvc/signed_obj.cpp new file mode 100644 index 000000000..20226fbe7 --- /dev/null +++ b/src/lib/cert/cvc/signed_obj.cpp @@ -0,0 +1,96 @@ +/* +* EAC SIGNED Object +* (C) 1999-2010 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Return a BER encoded X.509 object +*/ +std::vector EAC_Signed_Object::BER_encode() const + { + Pipe ber; + ber.start_msg(); + encode(ber, RAW_BER); + ber.end_msg(); + return unlock(ber.read_all()); + } + +/* +* Return a PEM encoded X.509 object +*/ +std::string EAC_Signed_Object::PEM_encode() const + { + Pipe pem; + pem.start_msg(); + encode(pem, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/* +* Return the algorithm used to sign this object +*/ +AlgorithmIdentifier EAC_Signed_Object::signature_algorithm() const + { + return sig_algo; + } + +bool EAC_Signed_Object::check_signature(Public_Key& pub_key, + const std::vector& sig) const + { + try + { + std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name()) + { + return false; + } + + std::string padding = sig_info[1]; + Signature_Format format = + (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + std::vector to_sign = tbs_data(); + + PK_Verifier verifier(pub_key, padding, format); + return verifier.verify_message(to_sign, sig); + } + catch(...) + { + return false; + } + } + +/* +* Try to decode the actual information +*/ +void EAC_Signed_Object::do_decode() + { + try { + force_decode(); + } + catch(Decoding_Error& e) + { + const std::string what = e.what(); + throw Decoding_Error(PEM_label_pref + " decoding failed (" + what + ")"); + } + catch(Invalid_Argument& e) + { + const std::string what = e.what(); + throw Decoding_Error(PEM_label_pref + " decoding failed (" + what + ")"); + } + } + +} diff --git a/src/lib/cert/cvc/signed_obj.h b/src/lib/cert/cvc/signed_obj.h new file mode 100644 index 000000000..ce2bd4dd7 --- /dev/null +++ b/src/lib/cert/cvc/signed_obj.h @@ -0,0 +1,96 @@ +/* +* EAC SIGNED Object +* (C) 2007 FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAC_SIGNED_OBJECT_H__ +#define BOTAN_EAC_SIGNED_OBJECT_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents abstract signed EAC object +*/ +class BOTAN_DLL EAC_Signed_Object + { + public: + /** + * Get the TBS (to-be-signed) data in this object. + * @return DER encoded TBS data of this object + */ + virtual std::vector tbs_data() const = 0; + + /** + * Get the signature of this object as a concatenation, i.e. if the + * signature consists of multiple parts (like in the case of ECDSA) + * these will be concatenated. + * @return signature as a concatenation of its parts + */ + + /* + NOTE: this is here only because abstract signature objects have + not yet been introduced + */ + virtual std::vector get_concat_sig() const = 0; + + /** + * Get the signature algorithm identifier used to sign this object. + * @result the signature algorithm identifier + */ + AlgorithmIdentifier signature_algorithm() const; + + /** + * Check the signature of this object. + * @param key the public key associated with this signed object + * @param sig the signature we are checking + * @return true if the signature was created by the private key + * associated with this public key + */ + bool check_signature(class Public_Key& key, + const std::vector& sig) const; + + /** + * Write this object DER encoded into a specified pipe. + * @param pipe the pipe to write the encoded object to + * @param encoding the encoding type to use + */ + virtual void encode(Pipe& pipe, + X509_Encoding encoding = PEM) const = 0; + + /** + * BER encode this object. + * @return result containing the BER representation of this object. + */ + std::vector BER_encode() const; + + /** + * PEM encode this object. + * @return result containing the PEM representation of this object. + */ + std::string PEM_encode() const; + + virtual ~EAC_Signed_Object() {} + protected: + void do_decode(); + EAC_Signed_Object() {} + + AlgorithmIdentifier sig_algo; + std::vector tbs_bits; + std::string PEM_label_pref; + std::vector PEM_labels_allowed; + private: + virtual void force_decode() = 0; + }; + +} + +#endif diff --git a/src/lib/cert/x509/cert_status.h b/src/lib/cert/x509/cert_status.h new file mode 100644 index 000000000..0ff5ad5f0 --- /dev/null +++ b/src/lib/cert/x509/cert_status.h @@ -0,0 +1,56 @@ +/* +* Result enums +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_PATH_RESULT_H__ +#define BOTAN_X509_PATH_RESULT_H__ + +#include + +namespace Botan { + +enum Certificate_Status_Code { + VERIFIED, + UNKNOWN_X509_ERROR, + CANNOT_ESTABLISH_TRUST, + CERT_CHAIN_TOO_LONG, + SIGNATURE_ERROR, + POLICY_ERROR, + INVALID_USAGE, + + SIGNATURE_METHOD_TOO_WEAK, + UNTRUSTED_HASH, + + CERT_MULTIPLE_ISSUERS_FOUND, + + CERT_FORMAT_ERROR, + CERT_ISSUER_NOT_FOUND, + CERT_NOT_YET_VALID, + CERT_HAS_EXPIRED, + CERT_IS_REVOKED, + + NO_REVOCATION_DATA, + + CRL_FORMAT_ERROR, + CRL_NOT_YET_VALID, + CRL_HAS_EXPIRED, + CRL_NOT_FOUND, + + OCSP_CERT_NOT_LISTED, + OCSP_NOT_YET_VALID, + OCSP_EXPIRED, + OCSP_BAD_STATUS, + OCSP_RESPONSE_GOOD, + + CA_CERT_CANNOT_SIGN, + CA_CERT_NOT_FOR_CERT_ISSUER, + CA_CERT_NOT_FOR_CRL_ISSUER +}; + + +} + +#endif diff --git a/src/lib/cert/x509/certstor.cpp b/src/lib/cert/x509/certstor.cpp new file mode 100644 index 000000000..e8b3a0718 --- /dev/null +++ b/src/lib/cert/x509/certstor.cpp @@ -0,0 +1,148 @@ +/* +* Certificate Store +* (C) 1999-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +const X509_CRL* Certificate_Store::find_crl(const X509_Certificate&) const + { + return nullptr; + } + +void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) + { + for(size_t i = 0; i != m_certs.size(); ++i) + { + if(m_certs[i] == cert) + return; + } + + m_certs.push_back(cert); + } + +std::vector Certificate_Store_In_Memory::all_subjects() const + { + std::vector subjects; + for(size_t i = 0; i != m_certs.size(); ++i) + subjects.push_back(m_certs[i].subject_dn()); + return subjects; + } + +namespace { + +const X509_Certificate* +cert_search(const X509_DN& subject_dn, const std::vector& key_id, + const std::vector& certs) + { + for(size_t i = 0; i != certs.size(); ++i) + { + // Only compare key ids if set in both call and in the cert + if(key_id.size()) + { + std::vector skid = certs[i].subject_key_id(); + + if(skid.size() && skid != key_id) // no match + continue; + } + + if(certs[i].subject_dn() == subject_dn) + return &certs[i]; + } + + return nullptr; + } + +} + +const X509_Certificate* +Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn, + const std::vector& key_id) const + { + return cert_search(subject_dn, key_id, m_certs); + } + +void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) + { + X509_DN crl_issuer = crl.issuer_dn(); + + for(size_t i = 0; i != m_crls.size(); ++i) + { + // Found an update of a previously existing one; replace it + if(m_crls[i].issuer_dn() == crl_issuer) + { + if(m_crls[i].this_update() <= crl.this_update()) + m_crls[i] = crl; + return; + } + } + + // Totally new CRL, add to the list + m_crls.push_back(crl); + } + +const X509_CRL* Certificate_Store_In_Memory::find_crl(const X509_Certificate& subject) const + { + const std::vector& key_id = subject.authority_key_id(); + + for(size_t i = 0; i != m_crls.size(); ++i) + { + // Only compare key ids if set in both call and in the CRL + if(key_id.size()) + { + std::vector akid = m_crls[i].authority_key_id(); + + if(akid.size() && akid != key_id) // no match + continue; + } + + if(m_crls[i].issuer_dn() == subject.issuer_dn()) + return &m_crls[i]; + } + + return nullptr; + } + +Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir) + { + if(dir == "") + return; + + boost::filesystem::recursive_directory_iterator i(dir); + boost::filesystem::recursive_directory_iterator end; + + while(i != end) + { + auto path = i->path(); + ++i; + + try + { + if(boost::filesystem::is_regular_file(path)) + m_certs.push_back(X509_Certificate(path.native())); + } + catch(...) {} + } + } + +const X509_Certificate* +Certificate_Store_Overlay::find_cert(const X509_DN& subject_dn, + const std::vector& key_id) const + { + return cert_search(subject_dn, key_id, m_certs); + } + +std::vector Certificate_Store_Overlay::all_subjects() const + { + std::vector subjects; + for(size_t i = 0; i != m_certs.size(); ++i) + subjects.push_back(m_certs[i].subject_dn()); + return subjects; + } + +} diff --git a/src/lib/cert/x509/certstor.h b/src/lib/cert/x509/certstor.h new file mode 100644 index 000000000..fc37d8327 --- /dev/null +++ b/src/lib/cert/x509/certstor.h @@ -0,0 +1,89 @@ +/* +* Certificate Store +* (C) 1999-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CERT_STORE_H__ +#define BOTAN_CERT_STORE_H__ + +#include +#include + +namespace Botan { + +/** +* Certificate Store Interface +*/ +class BOTAN_DLL Certificate_Store + { + public: + virtual ~Certificate_Store() {} + + /** + * Subject DN and (optionally) key identifier + */ + virtual const X509_Certificate* + find_cert(const X509_DN& subject_dn, const std::vector& key_id) const = 0; + + virtual const X509_CRL* find_crl(const X509_Certificate& subject) const; + + bool certificate_known(const X509_Certificate& cert) const + { + return find_cert(cert.subject_dn(), cert.subject_key_id()); + } + + // remove this (used by TLS::Server) + virtual std::vector all_subjects() const = 0; + }; + +/** +* In Memory Certificate Store +*/ +class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store + { + public: + /** + * Attempt to parse all files in dir (including subdirectories) + * as certificates. Ignores errors. + */ + Certificate_Store_In_Memory(const std::string& dir); + + Certificate_Store_In_Memory() {} + + void add_certificate(const X509_Certificate& cert); + + void add_crl(const X509_CRL& crl); + + std::vector all_subjects() const override; + + const X509_Certificate* find_cert( + const X509_DN& subject_dn, + const std::vector& key_id) const override; + + const X509_CRL* find_crl(const X509_Certificate& subject) const override; + private: + // TODO: Add indexing on the DN and key id to avoid linear search + std::vector m_certs; + std::vector m_crls; + }; + +class BOTAN_DLL Certificate_Store_Overlay : public Certificate_Store + { + public: + Certificate_Store_Overlay(const std::vector& certs) : + m_certs(certs) {} + + std::vector all_subjects() const override; + + const X509_Certificate* find_cert( + const X509_DN& subject_dn, + const std::vector& key_id) const override; + private: + const std::vector& m_certs; + }; + +} + +#endif diff --git a/src/lib/cert/x509/crl_ent.cpp b/src/lib/cert/x509/crl_ent.cpp new file mode 100644 index 000000000..a5663e6bb --- /dev/null +++ b/src/lib/cert/x509/crl_ent.cpp @@ -0,0 +1,103 @@ +/* +* CRL Entry +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create a CRL_Entry +*/ +CRL_Entry::CRL_Entry(bool t_on_unknown_crit) : + throw_on_unknown_critical(t_on_unknown_crit) + { + reason = UNSPECIFIED; + } + +/* +* Create a CRL_Entry +*/ +CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) : + throw_on_unknown_critical(false) + { + serial = cert.serial_number(); + time = X509_Time(std::chrono::system_clock::now()); + reason = why; + } + +/* +* Compare two CRL_Entrys for equality +*/ +bool operator==(const CRL_Entry& a1, const CRL_Entry& a2) + { + if(a1.serial_number() != a2.serial_number()) + return false; + if(a1.expire_time() != a2.expire_time()) + return false; + if(a1.reason_code() != a2.reason_code()) + return false; + return true; + } + +/* +* Compare two CRL_Entrys for inequality +*/ +bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2) + { + return !(a1 == a2); + } + +/* +* DER encode a CRL_Entry +*/ +void CRL_Entry::encode_into(DER_Encoder& der) const + { + Extensions extensions; + + extensions.add(new Cert_Extension::CRL_ReasonCode(reason)); + + der.start_cons(SEQUENCE) + .encode(BigInt::decode(serial)) + .encode(time) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded CRL_Entry +*/ +void CRL_Entry::decode_from(BER_Decoder& source) + { + BigInt serial_number_bn; + reason = UNSPECIFIED; + + BER_Decoder entry = source.start_cons(SEQUENCE); + + entry.decode(serial_number_bn).decode(time); + + if(entry.more_items()) + { + Extensions extensions(throw_on_unknown_critical); + entry.decode(extensions); + Data_Store info; + extensions.contents_to(info, info); + reason = CRL_Code(info.get1_u32bit("X509v3.CRLReasonCode")); + } + + entry.end_cons(); + + serial = BigInt::encode(serial_number_bn); + } + +} diff --git a/src/lib/cert/x509/crl_ent.h b/src/lib/cert/x509/crl_ent.h new file mode 100644 index 000000000..e68008b70 --- /dev/null +++ b/src/lib/cert/x509/crl_ent.h @@ -0,0 +1,95 @@ +/* +* CRL Entry +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CRL_ENTRY_H__ +#define BOTAN_CRL_ENTRY_H__ + +#include +#include + +namespace Botan { + +/** +* X.509v2 CRL Reason Code. +*/ +enum CRL_Code { + UNSPECIFIED = 0, + KEY_COMPROMISE = 1, + CA_COMPROMISE = 2, + AFFILIATION_CHANGED = 3, + SUPERSEDED = 4, + CESSATION_OF_OPERATION = 5, + CERTIFICATE_HOLD = 6, + REMOVE_FROM_CRL = 8, + PRIVLEDGE_WITHDRAWN = 9, + AA_COMPROMISE = 10, + + DELETE_CRL_ENTRY = 0xFF00, + OCSP_GOOD = 0xFF01, + OCSP_UNKNOWN = 0xFF02 +}; + +/** +* This class represents CRL entries +*/ +class BOTAN_DLL CRL_Entry : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + /** + * Get the serial number of the certificate associated with this entry. + * @return certificate's serial number + */ + std::vector serial_number() const { return serial; } + + /** + * Get the revocation date of the certificate associated with this entry + * @return certificate's revocation date + */ + X509_Time expire_time() const { return time; } + + /** + * Get the entries reason code + * @return reason code + */ + CRL_Code reason_code() const { return reason; } + + /** + * Construct an empty CRL entry. + */ + CRL_Entry(bool throw_on_unknown_critical_extension = false); + + /** + * Construct an CRL entry. + * @param cert the certificate to revoke + * @param reason the reason code to set in the entry + */ + CRL_Entry(const X509_Certificate& cert, + CRL_Code reason = UNSPECIFIED); + + private: + bool throw_on_unknown_critical; + std::vector serial; + X509_Time time; + CRL_Code reason; + }; + +/** +* Test two CRL entries for equality in all fields. +*/ +BOTAN_DLL bool operator==(const CRL_Entry&, const CRL_Entry&); + +/** +* Test two CRL entries for inequality in at least one field. +*/ +BOTAN_DLL bool operator!=(const CRL_Entry&, const CRL_Entry&); + +} + +#endif diff --git a/src/lib/cert/x509/info.txt b/src/lib/cert/x509/info.txt new file mode 100644 index 000000000..83512857f --- /dev/null +++ b/src/lib/cert/x509/info.txt @@ -0,0 +1,10 @@ +define X509_CERTIFICATES 20131128 +define OCSP 20131128 + + +datastor + + + +all -> boost_filesystem + diff --git a/src/lib/cert/x509/key_constraint.cpp b/src/lib/cert/x509/key_constraint.cpp new file mode 100644 index 000000000..8a4b3deb3 --- /dev/null +++ b/src/lib/cert/x509/key_constraint.cpp @@ -0,0 +1,69 @@ +/* +* KeyUsage +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace BER { + +/* +* Decode a BER encoded KeyUsage +*/ +void decode(BER_Decoder& source, Key_Constraints& key_usage) + { + BER_Object obj = source.get_next_object(); + + if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Bad tag for usage constraint", + obj.type_tag, obj.class_tag); + if(obj.value.size() != 2 && obj.value.size() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + const byte mask = (0xFF << obj.value[0]); + obj.value[obj.value.size()-1] &= mask; + + u16bit usage = 0; + for(size_t j = 1; j != obj.value.size(); ++j) + usage = (obj.value[j] << 8) | usage; + + key_usage = Key_Constraints(usage); + } + +} + +/* +* Find the allowable key constraints +*/ +Key_Constraints find_constraints(const Public_Key& pub_key, + Key_Constraints limits) + { + const std::string name = pub_key.algo_name(); + + size_t constraints = 0; + + if(name == "DH" || name == "ECDH") + constraints |= KEY_AGREEMENT; + + if(name == "RSA" || name == "ElGamal") + constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; + + if(name == "RSA" || name == "RW" || name == "NR" || + name == "DSA" || name == "ECDSA") + constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION; + + if(limits) + constraints &= limits; + + return Key_Constraints(constraints); + } + +} diff --git a/src/lib/cert/x509/key_constraint.h b/src/lib/cert/x509/key_constraint.h new file mode 100644 index 000000000..2c9b3778b --- /dev/null +++ b/src/lib/cert/x509/key_constraint.h @@ -0,0 +1,57 @@ +/* +* Enumerations +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENUMS_H__ +#define BOTAN_ENUMS_H__ + +#include + +namespace Botan { + +/** +* X.509v3 Key Constraints. +*/ +enum Key_Constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 32768, + NON_REPUDIATION = 16384, + KEY_ENCIPHERMENT = 8192, + DATA_ENCIPHERMENT = 4096, + KEY_AGREEMENT = 2048, + KEY_CERT_SIGN = 1024, + CRL_SIGN = 512, + ENCIPHER_ONLY = 256, + DECIPHER_ONLY = 128 +}; + +class Public_Key; + +/** +* Create the key constraints for a specific public key. +* @param pub_key the public key from which the basic set of +* constraints to be placed in the return value is derived +* @param limits additional limits that will be incorporated into the +* return value +* @return combination of key type specific constraints and +* additional limits +*/ + +BOTAN_DLL Key_Constraints find_constraints(const Public_Key& pub_key, + Key_Constraints limits); + +/** +* BER Decoding Function for key constraints +*/ +namespace BER { + +void BOTAN_DLL decode(BER_Decoder&, Key_Constraints&); + +} + +} + +#endif diff --git a/src/lib/cert/x509/ocsp.cpp b/src/lib/cert/x509/ocsp.cpp new file mode 100644 index 000000000..a118a9c4e --- /dev/null +++ b/src/lib/cert/x509/ocsp.cpp @@ -0,0 +1,251 @@ +/* +* OCSP +* (C) 2012,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +namespace { + +void decode_optional_list(BER_Decoder& ber, + ASN1_Tag tag, + std::vector& output) + { + BER_Object obj = ber.get_next_object(); + + if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)) + { + ber.push_back(obj); + return; + } + + BER_Decoder list(obj.value); + + while(list.more_items()) + { + BER_Object certbits = list.get_next_object(); + X509_Certificate cert(unlock(certbits.value)); + output.push_back(std::move(cert)); + } + } + +void check_signature(const std::vector& tbs_response, + const AlgorithmIdentifier& sig_algo, + const std::vector& signature, + const X509_Certificate& cert) + { + std::unique_ptr pub_key(cert.subject_public_key()); + + const std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + throw std::runtime_error("Information in OCSP response does not match cert"); + + std::string padding = sig_info[1]; + Signature_Format format = + (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + PK_Verifier verifier(*pub_key, padding, format); + + if(!verifier.verify_message(ASN1::put_in_sequence(tbs_response), signature)) + throw std::runtime_error("Signature on OCSP response does not verify"); + } + +void check_signature(const std::vector& tbs_response, + const AlgorithmIdentifier& sig_algo, + const std::vector& signature, + const Certificate_Store& trusted_roots, + const std::vector& certs) + { + if(certs.size() < 1) + throw std::invalid_argument("Short cert chain for check_signature"); + + if(trusted_roots.certificate_known(certs[0])) + return check_signature(tbs_response, sig_algo, signature, certs[0]); + + // Otherwise attempt to chain the signing cert to a trust root + + if(!certs[0].allowed_usage("PKIX.OCSPSigning")) + throw std::runtime_error("OCSP response cert does not allow OCSP signing"); + + auto result = x509_path_validate(certs, Path_Validation_Restrictions(), trusted_roots); + + if(!result.successful_validation()) + throw std::runtime_error("Certificate validation failure: " + result.result_string()); + + if(!trusted_roots.certificate_known(result.trust_root())) // not needed anymore? + throw std::runtime_error("Certificate chain roots in unknown/untrusted CA"); + + const std::vector& cert_path = result.cert_path(); + + check_signature(tbs_response, sig_algo, signature, cert_path[0]); + } + +} + +std::vector Request::BER_encode() const + { + CertID certid(m_issuer, m_subject); + + return DER_Encoder().start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .start_explicit(0) + .encode(static_cast(0)) // version # + .end_explicit() + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(certid) + .end_cons() + .end_cons() + .end_cons() + .end_cons().get_contents_unlocked(); + } + +std::string Request::base64_encode() const + { + return Botan::base64_encode(BER_encode()); + } + +Response::Response(const Certificate_Store& trusted_roots, + const std::vector& response_bits) + { + BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE); + + size_t resp_status = 0; + + response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); + + if(resp_status != 0) + throw std::runtime_error("OCSP response status " + std::to_string(resp_status)); + + if(response_outer.more_items()) + { + BER_Decoder response_bytes = + response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); + + response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), + "Unknown response type in OCSP response"); + + BER_Decoder basicresponse = + BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); + + std::vector tbs_bits; + AlgorithmIdentifier sig_algo; + std::vector signature; + std::vector certs; + + basicresponse.start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .end_cons() + .decode(sig_algo) + .decode(signature, BIT_STRING); + decode_optional_list(basicresponse, ASN1_Tag(0), certs); + + size_t responsedata_version = 0; + X509_DN name; + std::vector key_hash; + X509_Time produced_at; + Extensions extensions; + + BER_Decoder(tbs_bits) + .decode_optional(responsedata_version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional(name, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional_string(key_hash, ASN1_Tag(2), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode(produced_at) + + .decode_list(m_responses) + + .decode_optional(extensions, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + + if(certs.empty()) + { + if(auto cert = trusted_roots.find_cert(name, std::vector())) + certs.push_back(*cert); + else + throw std::runtime_error("Could not find certificate that signed OCSP response"); + } + + check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs); + } + + response_outer.end_cons(); + } + +Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const + { + for(const auto& response : m_responses) + { + if(response.certid().is_id_for(issuer, subject)) + { + X509_Time current_time(std::chrono::system_clock::now()); + + if(response.this_update() > current_time) + return Certificate_Status_Code::OCSP_NOT_YET_VALID; + + if(response.next_update().time_is_set() && current_time > response.next_update()) + return Certificate_Status_Code::OCSP_EXPIRED; + + if(response.cert_status() == 1) + return Certificate_Status_Code::CERT_IS_REVOKED; + else if(response.cert_status() == 0) + return Certificate_Status_Code::OCSP_RESPONSE_GOOD; + else + return Certificate_Status_Code::OCSP_BAD_STATUS; + } + } + + return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; + } + +Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + const Certificate_Store* trusted_roots) + { + const std::string responder_url = subject.ocsp_responder(); + + if(responder_url == "") + throw std::runtime_error("No OCSP responder specified"); + + OCSP::Request req(issuer, subject); + + auto http = HTTP::POST_sync(responder_url, + "application/ocsp-request", + req.BER_encode()); + + http.throw_unless_ok(); + + // Check the MIME type? + + OCSP::Response response(*trusted_roots, http.body()); + + return response; + } + +} + +} diff --git a/src/lib/cert/x509/ocsp.h b/src/lib/cert/x509/ocsp.h new file mode 100644 index 000000000..b2a06b9a4 --- /dev/null +++ b/src/lib/cert/x509/ocsp.h @@ -0,0 +1,61 @@ +/* +* OCSP +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OCSP_H__ +#define BOTAN_OCSP_H__ + +#include +#include + +namespace Botan { + +class Certificate_Store; + +namespace OCSP { + +class BOTAN_DLL Request + { + public: + Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert) : + m_issuer(issuer_cert), + m_subject(subject_cert) + {} + + std::vector BER_encode() const; + + std::string base64_encode() const; + + const X509_Certificate& issuer() const { return m_issuer; } + + const X509_Certificate& subject() const { return m_subject; } + private: + X509_Certificate m_issuer, m_subject; + }; + +class BOTAN_DLL Response + { + public: + Response(const Certificate_Store& trusted_roots, + const std::vector& response); + + Certificate_Status_Code status_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; + + private: + std::vector m_responses; + }; + +BOTAN_DLL Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + const Certificate_Store* trusted_roots); + +} + +} + +#endif diff --git a/src/lib/cert/x509/ocsp_types.cpp b/src/lib/cert/x509/ocsp_types.cpp new file mode 100644 index 000000000..be41499ee --- /dev/null +++ b/src/lib/cert/x509/ocsp_types.cpp @@ -0,0 +1,121 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +CertID::CertID(const X509_Certificate& issuer, + const X509_Certificate& subject) + { + /* + In practice it seems some responders, including, notably, + ocsp.verisign.com, will reject anything but SHA-1 here + */ + std::unique_ptr hash(get_hash("SHA-160")); + + m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); + m_issuer_key_hash = unlock(hash->process(extract_key_bitstr(issuer))); + m_issuer_dn_hash = unlock(hash->process(subject.raw_issuer_dn())); + m_subject_serial = BigInt::decode(subject.serial_number()); + } + +std::vector CertID::extract_key_bitstr(const X509_Certificate& cert) const + { + const auto key_bits = cert.subject_public_key_bits(); + + AlgorithmIdentifier public_key_algid; + std::vector public_key_bitstr; + + BER_Decoder(key_bits) + .decode(public_key_algid) + .decode(public_key_bitstr, BIT_STRING); + + return public_key_bitstr; + } + +bool CertID::is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const + { + try + { + if(BigInt::decode(subject.serial_number()) != m_subject_serial) + return false; + + std::unique_ptr hash(get_hash(OIDS::lookup(m_hash_id.oid))); + + if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) + return false; + + if(m_issuer_key_hash != unlock(hash->process(extract_key_bitstr(issuer)))) + return false; + } + catch(...) + { + return false; + } + + return true; + } + +void CertID::encode_into(class DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .encode(m_hash_id) + .encode(m_issuer_dn_hash, OCTET_STRING) + .encode(m_issuer_key_hash, OCTET_STRING) + .encode(m_subject_serial) + .end_cons(); + } + +void CertID::decode_from(class BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .decode(m_hash_id) + .decode(m_issuer_dn_hash, OCTET_STRING) + .decode(m_issuer_key_hash, OCTET_STRING) + .decode(m_subject_serial) + .end_cons(); + + } + +void SingleResponse::encode_into(class DER_Encoder&) const + { + throw std::runtime_error("Not implemented (SingleResponse::encode_into)"); + } + +void SingleResponse::decode_from(class BER_Decoder& from) + { + BER_Object cert_status; + Extensions extensions; + + from.start_cons(SEQUENCE) + .decode(m_certid) + .get_next(cert_status) + .decode(m_thisupdate) + .decode_optional(m_nextupdate, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .decode_optional(extensions, + ASN1_Tag(1), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .end_cons(); + + m_cert_status = cert_status.type_tag; + } + +} + +} diff --git a/src/lib/cert/x509/ocsp_types.h b/src/lib/cert/x509/ocsp_types.h new file mode 100644 index 000000000..a2983f10b --- /dev/null +++ b/src/lib/cert/x509/ocsp_types.h @@ -0,0 +1,67 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OCSP_TYPES_H__ +#define BOTAN_OCSP_TYPES_H__ + +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +class BOTAN_DLL CertID : public ASN1_Object + { + public: + CertID() {} + + CertID(const X509_Certificate& issuer, + const X509_Certificate& subject); + + bool is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + private: + std::vector extract_key_bitstr(const X509_Certificate& cert) const; + + AlgorithmIdentifier m_hash_id; + std::vector m_issuer_dn_hash; + std::vector m_issuer_key_hash; + BigInt m_subject_serial; + }; + +class BOTAN_DLL SingleResponse : public ASN1_Object + { + public: + const CertID& certid() const { return m_certid; } + + size_t cert_status() const { return m_cert_status; } + + X509_Time this_update() const { return m_thisupdate; } + + X509_Time next_update() const { return m_nextupdate; } + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + private: + CertID m_certid; + size_t m_cert_status = 2; // unknown + X509_Time m_thisupdate; + X509_Time m_nextupdate; + }; + +} + +} + +#endif diff --git a/src/lib/cert/x509/pkcs10.cpp b/src/lib/cert/x509/pkcs10.cpp new file mode 100644 index 000000000..c67f74142 --- /dev/null +++ b/src/lib/cert/x509/pkcs10.cpp @@ -0,0 +1,208 @@ +/* +* PKCS #10 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* PKCS10_Request Constructor +*/ +PKCS10_Request::PKCS10_Request(DataSource& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + do_decode(); + } + +/* +* PKCS10_Request Constructor +*/ +PKCS10_Request::PKCS10_Request(const std::string& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + do_decode(); + } + +/* +* PKCS10_Request Constructor +*/ +PKCS10_Request::PKCS10_Request(const std::vector& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + do_decode(); + } + +/* +* Deocde the CertificateRequestInfo +*/ +void PKCS10_Request::force_decode() + { + BER_Decoder cert_req_info(tbs_bits); + + size_t version; + cert_req_info.decode(version); + if(version != 0) + throw Decoding_Error("Unknown version code in PKCS #10 request: " + + std::to_string(version)); + + X509_DN dn_subject; + cert_req_info.decode(dn_subject); + + info.add(dn_subject.contents()); + + BER_Object public_key = cert_req_info.get_next_object(); + if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", + public_key.type_tag, public_key.class_tag); + + info.add("X509.Certificate.public_key", + PEM_Code::encode( + ASN1::put_in_sequence(unlock(public_key.value)), + "PUBLIC KEY" + ) + ); + + BER_Object attr_bits = cert_req_info.get_next_object(); + + if(attr_bits.type_tag == 0 && + attr_bits.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + BER_Decoder attributes(attr_bits.value); + while(attributes.more_items()) + { + Attribute attr; + attributes.decode(attr); + handle_attribute(attr); + } + attributes.verify_end(); + } + else if(attr_bits.type_tag != NO_OBJECT) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", + attr_bits.type_tag, attr_bits.class_tag); + + cert_req_info.verify_end(); + + if(!this->check_signature(subject_public_key())) + throw Decoding_Error("PKCS #10 request: Bad signature detected"); + } + +/* +* Handle attributes in a PKCS #10 request +*/ +void PKCS10_Request::handle_attribute(const Attribute& attr) + { + BER_Decoder value(attr.parameters); + + if(attr.oid == OIDS::lookup("PKCS9.EmailAddress")) + { + ASN1_String email; + value.decode(email); + info.add("RFC822", email.value()); + } + else if(attr.oid == OIDS::lookup("PKCS9.ChallengePassword")) + { + ASN1_String challenge_password; + value.decode(challenge_password); + info.add("PKCS9.ChallengePassword", challenge_password.value()); + } + else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest")) + { + Extensions extensions; + value.decode(extensions).verify_end(); + + Data_Store issuer_info; + extensions.contents_to(info, issuer_info); + } + } + +/* +* Return the challenge password (if any) +*/ +std::string PKCS10_Request::challenge_password() const + { + return info.get1("PKCS9.ChallengePassword"); + } + +/* +* Return the name of the requestor +*/ +X509_DN PKCS10_Request::subject_dn() const + { + return create_dn(info); + } + +/* +* Return the public key of the requestor +*/ +std::vector PKCS10_Request::raw_public_key() const + { + DataSource_Memory source(info.get1("X509.Certificate.public_key")); + return unlock(PEM_Code::decode_check_label(source, "PUBLIC KEY")); + } + +/* +* Return the public key of the requestor +*/ +Public_Key* PKCS10_Request::subject_public_key() const + { + DataSource_Memory source(info.get1("X509.Certificate.public_key")); + return X509::load_key(source); + } + +/* +* Return the alternative names of the requestor +*/ +AlternativeName PKCS10_Request::subject_alt_name() const + { + return create_alt_name(info); + } + +/* +* Return the key constraints (if any) +*/ +Key_Constraints PKCS10_Request::constraints() const + { + return Key_Constraints(info.get1_u32bit("X509v3.KeyUsage", NO_CONSTRAINTS)); + } + +/* +* Return the extendend key constraints (if any) +*/ +std::vector PKCS10_Request::ex_constraints() const + { + std::vector oids = info.get("X509v3.ExtendedKeyUsage"); + + std::vector result; + for(size_t i = 0; i != oids.size(); ++i) + result.push_back(OID(oids[i])); + return result; + } + +/* +* Return is a CA certificate is requested +*/ +bool PKCS10_Request::is_CA() const + { + return (info.get1_u32bit("X509v3.BasicConstraints.is_ca") > 0); + } + +/* +* Return the desired path limit (if any) +*/ +u32bit PKCS10_Request::path_limit() const + { + return info.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0); + } + +} diff --git a/src/lib/cert/x509/pkcs10.h b/src/lib/cert/x509/pkcs10.h new file mode 100644 index 000000000..b54425133 --- /dev/null +++ b/src/lib/cert/x509/pkcs10.h @@ -0,0 +1,111 @@ +/* +* PKCS #10 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PKCS10_H__ +#define BOTAN_PKCS10_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* PKCS #10 Certificate Request. +*/ +class BOTAN_DLL PKCS10_Request : public X509_Object + { + public: + /** + * Get the subject public key. + * @return subject public key + */ + Public_Key* subject_public_key() const; + + /** + * Get the raw DER encoded public key. + * @return raw DER encoded public key + */ + std::vector raw_public_key() const; + + /** + * Get the subject DN. + * @return subject DN + */ + X509_DN subject_dn() const; + + /** + * Get the subject alternative name. + * @return subject alternative name. + */ + AlternativeName subject_alt_name() const; + + /** + * Get the key constraints for the key associated with this + * PKCS#10 object. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the extendend key constraints (if any). + * @return extended key constraints + */ + std::vector ex_constraints() const; + + /** + * Find out whether this is a CA request. + * @result true if it is a CA request, false otherwise. + */ + bool is_CA() const; + + /** + * Return the constraint on the path length defined + * in the BasicConstraints extension. + * @return path limit + */ + u32bit path_limit() const; + + /** + * Get the challenge password for this request + * @return challenge password for this request + */ + std::string challenge_password() const; + + /** + * Create a PKCS#10 Request from a data source. + * @param source the data source providing the DER encoded request + */ + PKCS10_Request(DataSource& source); + + /** + * Create a PKCS#10 Request from a file. + * @param filename the name of the file containing the DER or PEM + * encoded request file + */ + PKCS10_Request(const std::string& filename); + + /** + * Create a PKCS#10 Request from binary data. + * @param vec a std::vector containing the DER value + */ + PKCS10_Request(const std::vector& vec); + private: + void force_decode(); + void handle_attribute(const Attribute&); + + Data_Store info; + }; + +} + +#endif diff --git a/src/lib/cert/x509/x509_ca.cpp b/src/lib/cert/x509/x509_ca.cpp new file mode 100644 index 000000000..486d769ef --- /dev/null +++ b/src/lib/cert/x509/x509_ca.cpp @@ -0,0 +1,254 @@ +/* +* X.509 Certificate Authority +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Load the certificate and private key +*/ +X509_CA::X509_CA(const X509_Certificate& c, + const Private_Key& key, + const std::string& hash_fn) : cert(c) + { + if(!cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + signer = choose_sig_format(key, hash_fn, ca_sig_algo); + } + +/* +* X509_CA Destructor +*/ +X509_CA::~X509_CA() + { + delete signer; + } + +/* +* Sign a PKCS #10 certificate request +*/ +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after) + { + Key_Constraints constraints; + if(req.is_CA()) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + { + std::unique_ptr key(req.subject_public_key()); + constraints = find_constraints(*key, req.constraints()); + } + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), + true); + + extensions.add(new Cert_Extension::Key_Usage(constraints), true); + + extensions.add(new Cert_Extension::Authority_Key_ID(cert.subject_key_id())); + extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key())); + + extensions.add( + new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); + + extensions.add( + new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); + + return make_cert(signer, rng, ca_sig_algo, + req.raw_public_key(), + not_before, not_after, + cert.subject_dn(), req.subject_dn(), + extensions); + } + +/* +* Create a new certificate +*/ +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const std::vector& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions) + { + const size_t X509_CERT_VERSION = 3; + const size_t SERIAL_BITS = 128; + + BigInt serial_no(rng, SERIAL_BITS); + + const std::vector cert = X509_Object::make_signed( + signer, rng, sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .start_explicit(0) + .encode(X509_CERT_VERSION-1) + .end_explicit() + + .encode(serial_no) + + .encode(sig_algo) + .encode(issuer_dn) + + .start_cons(SEQUENCE) + .encode(not_before) + .encode(not_after) + .end_cons() + + .encode(subject_dn) + .raw_bytes(pub_key) + + .start_explicit(3) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents()); + + return X509_Certificate(cert); + } + +/* +* Create a new, empty CRL +*/ +X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, + u32bit next_update) const + { + std::vector empty; + return make_crl(empty, 1, next_update, rng); + } + +/* +* Update a CRL with new entries +*/ +X509_CRL X509_CA::update_crl(const X509_CRL& crl, + const std::vector& new_revoked, + RandomNumberGenerator& rng, + u32bit next_update) const + { + std::vector revoked = crl.get_revoked(); + + std::copy(new_revoked.begin(), new_revoked.end(), + std::back_inserter(revoked)); + + return make_crl(revoked, crl.crl_number() + 1, next_update, rng); + } + +/* +* Create a CRL +*/ +X509_CRL X509_CA::make_crl(const std::vector& revoked, + u32bit crl_number, u32bit next_update, + RandomNumberGenerator& rng) const + { + const size_t X509_CRL_VERSION = 2; + + if(next_update == 0) + next_update = timespec_to_u32bit("7d"); + + // Totally stupid: ties encoding logic to the return of std::time!! + auto current_time = std::chrono::system_clock::now(); + auto expire_time = current_time + std::chrono::seconds(next_update); + + Extensions extensions; + extensions.add( + new Cert_Extension::Authority_Key_ID(cert.subject_key_id())); + extensions.add(new Cert_Extension::CRL_Number(crl_number)); + + const std::vector crl = X509_Object::make_signed( + signer, rng, ca_sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .encode(X509_CRL_VERSION-1) + .encode(ca_sig_algo) + .encode(cert.issuer_dn()) + .encode(X509_Time(current_time)) + .encode(X509_Time(expire_time)) + .encode_if(revoked.size() > 0, + DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(revoked) + .end_cons() + ) + .start_explicit(0) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents()); + + return X509_CRL(crl); + } + +/* +* Return the CA's certificate +*/ +X509_Certificate X509_CA::ca_certificate() const + { + return cert; + } + +/* +* Choose a signing format for the key +*/ +PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, + AlgorithmIdentifier& sig_algo) + { + std::string padding; + + const std::string algo_name = key.algo_name(); + + const HashFunction* proto_hash = retrieve_hash(hash_fn); + if(!proto_hash) + throw Algorithm_Not_Found(hash_fn); + + if(key.max_input_bits() < proto_hash->output_length()*8) + throw Invalid_Argument("Key is too small for chosen hash function"); + + if(algo_name == "RSA") + padding = "EMSA3"; + else if(algo_name == "DSA") + padding = "EMSA1"; + else if(algo_name == "ECDSA") + padding = "EMSA1_BSI"; + else + throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + + Signature_Format format = + (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363; + + padding = padding + '(' + proto_hash->name() + ')'; + + sig_algo.oid = OIDS::lookup(algo_name + "/" + padding); + sig_algo.parameters = key.algorithm_identifier().parameters; + + return new PK_Signer(key, padding, format); + } + +} diff --git a/src/lib/cert/x509/x509_ca.h b/src/lib/cert/x509/x509_ca.h new file mode 100644 index 000000000..d37b02eaf --- /dev/null +++ b/src/lib/cert/x509/x509_ca.h @@ -0,0 +1,130 @@ +/* +* X.509 Certificate Authority +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_CA_H__ +#define BOTAN_X509_CA_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents X.509 Certificate Authorities (CAs). +*/ +class BOTAN_DLL X509_CA + { + public: + + /** + * Sign a PKCS#10 Request. + * @param req the request to sign + * @param rng the rng to use + * @param not_before the starting time for the certificate + * @param not_after the expiration time for the certificate + * @return resulting certificate + */ + X509_Certificate sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after); + + /** + * Get the certificate of this CA. + * @return CA certificate + */ + X509_Certificate ca_certificate() const; + + /** + * Create a new and empty CRL for this CA. + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + * @return new CRL + */ + X509_CRL new_crl(RandomNumberGenerator& rng, + u32bit next_update = 0) const; + + /** + * Create a new CRL by with additional entries. + * @param last_crl the last CRL of this CA to add the new entries to + * @param new_entries contains the new CRL entries to be added to the CRL + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + */ + X509_CRL update_crl(const X509_CRL& last_crl, + const std::vector& new_entries, + RandomNumberGenerator& rng, + u32bit next_update = 0) const; + + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param sig_algo the signature algorithm identifier + * @param pub_key the serialized public key + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const std::vector& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions); + + /** + * Create a new CA object. + * @param ca_certificate the certificate of the CA + * @param key the private key of the CA + * @param hash_fn name of a hash function to use for signing + */ + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn); + + X509_CA(const X509_CA&) = delete; + X509_CA& operator=(const X509_CA&) = delete; + + ~X509_CA(); + private: + X509_CRL make_crl(const std::vector& entries, + u32bit crl_number, u32bit next_update, + RandomNumberGenerator& rng) const; + + AlgorithmIdentifier ca_sig_algo; + X509_Certificate cert; + PK_Signer* signer; + }; + +/** +* Choose the default signature format for a certain public key signature +* scheme. +* @param key will be the key to choose a padding scheme for +* @param hash_fn is the desired hash function +* @param alg_id will be set to the chosen scheme +* @return A PK_Signer object for generating signatures +*/ +BOTAN_DLL PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, + AlgorithmIdentifier& alg_id); + +} + +#endif diff --git a/src/lib/cert/x509/x509_crl.cpp b/src/lib/cert/x509/x509_crl.cpp new file mode 100644 index 000000000..29495a627 --- /dev/null +++ b/src/lib/cert/x509/x509_crl.cpp @@ -0,0 +1,191 @@ +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Load a X.509 CRL +*/ +X509_CRL::X509_CRL(DataSource& in, bool touc) : + X509_Object(in, "X509 CRL/CRL"), throw_on_unknown_critical(touc) + { + do_decode(); + } + +/* +* Load a X.509 CRL +*/ +X509_CRL::X509_CRL(const std::string& in, bool touc) : + X509_Object(in, "CRL/X509 CRL"), throw_on_unknown_critical(touc) + { + do_decode(); + } + +X509_CRL::X509_CRL(const std::vector& in, bool touc) : + X509_Object(in, "CRL/X509 CRL"), throw_on_unknown_critical(touc) + { + do_decode(); + } + +/** +* Check if this particular certificate is listed in the CRL +*/ +bool X509_CRL::is_revoked(const X509_Certificate& cert) const + { + /* + If the cert wasn't issued by the CRL issuer, it's possible the cert + is revoked, but not by this CRL. Maybe throw an exception instead? + */ + if(cert.issuer_dn() != issuer_dn()) + return false; + + std::vector crl_akid = authority_key_id(); + std::vector cert_akid = cert.authority_key_id(); + + if(!crl_akid.empty() && !cert_akid.empty()) + if(crl_akid != cert_akid) + return false; + + std::vector cert_serial = cert.serial_number(); + + bool is_revoked = false; + + for(size_t i = 0; i != revoked.size(); ++i) + { + if(cert_serial == revoked[i].serial_number()) + { + if(revoked[i].reason_code() == REMOVE_FROM_CRL) + is_revoked = false; + else + is_revoked = true; + } + } + + return is_revoked; + } + +/* +* Decode the TBSCertList data +*/ +void X509_CRL::force_decode() + { + BER_Decoder tbs_crl(tbs_bits); + + size_t version; + tbs_crl.decode_optional(version, INTEGER, UNIVERSAL); + + if(version != 0 && version != 1) + throw X509_CRL_Error("Unknown X.509 CRL version " + + std::to_string(version+1)); + + AlgorithmIdentifier sig_algo_inner; + tbs_crl.decode(sig_algo_inner); + + if(sig_algo != sig_algo_inner) + throw X509_CRL_Error("Algorithm identifier mismatch"); + + X509_DN dn_issuer; + tbs_crl.decode(dn_issuer); + info.add(dn_issuer.contents()); + + X509_Time start, end; + tbs_crl.decode(start).decode(end); + info.add("X509.CRL.start", start.readable_string()); + info.add("X509.CRL.end", end.readable_string()); + + BER_Object next = tbs_crl.get_next_object(); + + if(next.type_tag == SEQUENCE && next.class_tag == CONSTRUCTED) + { + BER_Decoder cert_list(next.value); + + while(cert_list.more_items()) + { + CRL_Entry entry(throw_on_unknown_critical); + cert_list.decode(entry); + revoked.push_back(entry); + } + next = tbs_crl.get_next_object(); + } + + if(next.type_tag == 0 && + next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + BER_Decoder crl_options(next.value); + + Extensions extensions(throw_on_unknown_critical); + + crl_options.decode(extensions).verify_end(); + + extensions.contents_to(info, info); + + next = tbs_crl.get_next_object(); + } + + if(next.type_tag != NO_OBJECT) + throw X509_CRL_Error("Unknown tag in CRL"); + + tbs_crl.verify_end(); + } + +/* +* Return the list of revoked certificates +*/ +std::vector X509_CRL::get_revoked() const + { + return revoked; + } + +/* +* Return the distinguished name of the issuer +*/ +X509_DN X509_CRL::issuer_dn() const + { + return create_dn(info); + } + +/* +* Return the key identifier of the issuer +*/ +std::vector X509_CRL::authority_key_id() const + { + return info.get1_memvec("X509v3.AuthorityKeyIdentifier"); + } + +/* +* Return the CRL number of this CRL +*/ +u32bit X509_CRL::crl_number() const + { + return info.get1_u32bit("X509v3.CRLNumber"); + } + +/* +* Return the issue data of the CRL +*/ +X509_Time X509_CRL::this_update() const + { + return info.get1("X509.CRL.start"); + } + +/* +* Return the date when a new CRL will be issued +*/ +X509_Time X509_CRL::next_update() const + { + return info.get1("X509.CRL.end"); + } + +} diff --git a/src/lib/cert/x509/x509_crl.h b/src/lib/cert/x509/x509_crl.h new file mode 100644 index 000000000..3e45df121 --- /dev/null +++ b/src/lib/cert/x509/x509_crl.h @@ -0,0 +1,111 @@ +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_CRL_H__ +#define BOTAN_X509_CRL_H__ + +#include +#include +#include + +namespace Botan { + +class X509_Certificate; + +/** +* This class represents X.509 Certificate Revocation Lists (CRLs). +*/ +class BOTAN_DLL X509_CRL : public X509_Object + { + public: + /** + * This class represents CRL related errors. + */ + struct BOTAN_DLL X509_CRL_Error : public Exception + { + X509_CRL_Error(const std::string& error) : + Exception("X509_CRL: " + error) {} + }; + + /** + * Check if this particular certificate is listed in the CRL + */ + bool is_revoked(const X509_Certificate& cert) const; + + /** + * Get the entries of this CRL in the form of a vector. + * @return vector containing the entries of this CRL. + */ + std::vector get_revoked() const; + + /** + * Get the issuer DN of this CRL. + * @return CRLs issuer DN + */ + X509_DN issuer_dn() const; + + /** + * Get the AuthorityKeyIdentifier of this CRL. + * @return this CRLs AuthorityKeyIdentifier + */ + std::vector authority_key_id() const; + + /** + * Get the serial number of this CRL. + * @return CRLs serial number + */ + u32bit crl_number() const; + + /** + * Get the CRL's thisUpdate value. + * @return CRLs thisUpdate + */ + X509_Time this_update() const; + + /** + * Get the CRL's nextUpdate value. + * @return CRLs nextdUpdate + */ + X509_Time next_update() const; + + /** + * Construct a CRL from a data source. + * @param source the data source providing the DER or PEM encoded CRL. + * @param throw_on_unknown_critical should we throw an exception + * if an unknown CRL extension marked as critical is encountered. + */ + X509_CRL(DataSource& source, bool throw_on_unknown_critical = false); + + /** + * Construct a CRL from a file containing the DER or PEM encoded CRL. + * @param filename the name of the CRL file + * @param throw_on_unknown_critical should we throw an exception + * if an unknown CRL extension marked as critical is encountered. + */ + X509_CRL(const std::string& filename, + bool throw_on_unknown_critical = false); + + /** + * Construct a CRL from a binary vector + * @param vec the binary (DER) representation of the CRL + * @param throw_on_unknown_critical should we throw an exception + * if an unknown CRL extension marked as critical is encountered. + */ + X509_CRL(const std::vector& vec, + bool throw_on_unknown_critical = false); + + private: + void force_decode(); + + bool throw_on_unknown_critical; + std::vector revoked; + Data_Store info; + }; + +} + +#endif diff --git a/src/lib/cert/x509/x509_ext.cpp b/src/lib/cert/x509/x509_ext.cpp new file mode 100644 index 000000000..7cef2969b --- /dev/null +++ b/src/lib/cert/x509/x509_ext.cpp @@ -0,0 +1,660 @@ +/* +* X.509 Certificate Extensions +* (C) 1999-2010,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* List of X.509 Certificate Extensions +*/ +Certificate_Extension* Extensions::get_extension(const OID& oid) + { +#define X509_EXTENSION(NAME, TYPE) \ + if(OIDS::name_of(oid, NAME)) \ + return new Cert_Extension::TYPE(); + + X509_EXTENSION("X509v3.KeyUsage", Key_Usage); + X509_EXTENSION("X509v3.BasicConstraints", Basic_Constraints); + X509_EXTENSION("X509v3.SubjectKeyIdentifier", Subject_Key_ID); + X509_EXTENSION("X509v3.AuthorityKeyIdentifier", Authority_Key_ID); + X509_EXTENSION("X509v3.ExtendedKeyUsage", Extended_Key_Usage); + X509_EXTENSION("X509v3.IssuerAlternativeName", Issuer_Alternative_Name); + X509_EXTENSION("X509v3.SubjectAlternativeName", Subject_Alternative_Name); + X509_EXTENSION("X509v3.CertificatePolicies", Certificate_Policies); + X509_EXTENSION("X509v3.CRLDistributionPoints", CRL_Distribution_Points); + X509_EXTENSION("PKIX.AuthorityInformationAccess", Authority_Information_Access); + X509_EXTENSION("X509v3.CRLNumber", CRL_Number); + X509_EXTENSION("X509v3.ReasonCode", CRL_ReasonCode); + + return nullptr; + } + +/* +* Extensions Copy Constructor +*/ +Extensions::Extensions(const Extensions& extensions) : ASN1_Object() + { + *this = extensions; + } + +/* +* Extensions Assignment Operator +*/ +Extensions& Extensions::operator=(const Extensions& other) + { + for(size_t i = 0; i != extensions.size(); ++i) + delete extensions[i].first; + extensions.clear(); + + for(size_t i = 0; i != other.extensions.size(); ++i) + extensions.push_back( + std::make_pair(other.extensions[i].first->copy(), + other.extensions[i].second)); + + return (*this); + } + +/* +* Return the OID of this extension +*/ +OID Certificate_Extension::oid_of() const + { + return OIDS::lookup(oid_name()); + } + +void Extensions::add(Certificate_Extension* extn, bool critical) + { + extensions.push_back(std::make_pair(extn, critical)); + } + +/* +* Encode an Extensions list +*/ +void Extensions::encode_into(DER_Encoder& to_object) const + { + for(size_t i = 0; i != extensions.size(); ++i) + { + const Certificate_Extension* ext = extensions[i].first; + const bool is_critical = extensions[i].second; + + const bool should_encode = ext->should_encode(); + + if(should_encode) + { + to_object.start_cons(SEQUENCE) + .encode(ext->oid_of()) + .encode_optional(is_critical, false) + .encode(ext->encode_inner(), OCTET_STRING) + .end_cons(); + } + } + } + +/* +* Decode a list of Extensions +*/ +void Extensions::decode_from(BER_Decoder& from_source) + { + for(size_t i = 0; i != extensions.size(); ++i) + delete extensions[i].first; + extensions.clear(); + + BER_Decoder sequence = from_source.start_cons(SEQUENCE); + + while(sequence.more_items()) + { + OID oid; + std::vector value; + bool critical; + + sequence.start_cons(SEQUENCE) + .decode(oid) + .decode_optional(critical, BOOLEAN, UNIVERSAL, false) + .decode(value, OCTET_STRING) + .verify_end() + .end_cons(); + + Certificate_Extension* ext = get_extension(oid); + + if(!ext) + { + if(!critical || !should_throw) + continue; + + throw Decoding_Error("Encountered unknown X.509 extension marked " + "as critical; OID = " + oid.as_string()); + } + + ext->decode_inner(value); + + extensions.push_back(std::make_pair(ext, critical)); + } + sequence.verify_end(); + } + +/* +* Write the extensions to an info store +*/ +void Extensions::contents_to(Data_Store& subject_info, + Data_Store& issuer_info) const + { + for(size_t i = 0; i != extensions.size(); ++i) + extensions[i].first->contents_to(subject_info, issuer_info); + } + +/* +* Delete an Extensions list +*/ +Extensions::~Extensions() + { + for(size_t i = 0; i != extensions.size(); ++i) + delete extensions[i].first; + } + +namespace Cert_Extension { + +/* +* Checked accessor for the path_limit member +*/ +size_t Basic_Constraints::get_path_limit() const + { + if(!is_ca) + throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); + return path_limit; + } + +/* +* Encode the extension +*/ +std::vector Basic_Constraints::encode_inner() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_if(is_ca, + DER_Encoder() + .encode(is_ca) + .encode_optional(path_limit, NO_CERT_PATH_LIMIT) + ) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void Basic_Constraints::decode_inner(const std::vector& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional(is_ca, BOOLEAN, UNIVERSAL, false) + .decode_optional(path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT) + .verify_end() + .end_cons(); + + if(is_ca == false) + path_limit = 0; + } + +/* +* Return a textual representation +*/ +void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.BasicConstraints.is_ca", (is_ca ? 1 : 0)); + subject.add("X509v3.BasicConstraints.path_constraint", path_limit); + } + +/* +* Encode the extension +*/ +std::vector Key_Usage::encode_inner() const + { + if(constraints == NO_CONSTRAINTS) + throw Encoding_Error("Cannot encode zero usage constraints"); + + const size_t unused_bits = low_bit(constraints) - 1; + + std::vector der; + der.push_back(BIT_STRING); + der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); + der.push_back(unused_bits % 8); + der.push_back((constraints >> 8) & 0xFF); + if(constraints & 0xFF) + der.push_back(constraints & 0xFF); + + return der; + } + +/* +* Decode the extension +*/ +void Key_Usage::decode_inner(const std::vector& in) + { + BER_Decoder ber(in); + + BER_Object obj = ber.get_next_object(); + + if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Bad tag for usage constraint", + obj.type_tag, obj.class_tag); + + if(obj.value.size() != 2 && obj.value.size() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + obj.value[obj.value.size()-1] &= (0xFF << obj.value[0]); + + u16bit usage = 0; + for(size_t i = 1; i != obj.value.size(); ++i) + usage = (obj.value[i] << 8) | usage; + + constraints = Key_Constraints(usage); + } + +/* +* Return a textual representation +*/ +void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.KeyUsage", constraints); + } + +/* +* Encode the extension +*/ +std::vector Subject_Key_ID::encode_inner() const + { + return DER_Encoder().encode(key_id, OCTET_STRING).get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void Subject_Key_ID::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(key_id, OCTET_STRING).verify_end(); + } + +/* +* Return a textual representation +*/ +void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.SubjectKeyIdentifier", key_id); + } + +/* +* Subject_Key_ID Constructor +*/ +Subject_Key_ID::Subject_Key_ID(const std::vector& pub_key) + { + SHA_160 hash; + key_id = unlock(hash.process(pub_key)); + } + +/* +* Encode the extension +*/ +std::vector Authority_Key_ID::encode_inner() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void Authority_Key_ID::decode_inner(const std::vector& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional_string(key_id, OCTET_STRING, 0); + } + +/* +* Return a textual representation +*/ +void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const + { + if(key_id.size()) + issuer.add("X509v3.AuthorityKeyIdentifier", key_id); + } + +/* +* Encode the extension +*/ +std::vector Alternative_Name::encode_inner() const + { + return DER_Encoder().encode(alt_name).get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void Alternative_Name::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(alt_name); + } + +/* +* Return a textual representation +*/ +void Alternative_Name::contents_to(Data_Store& subject_info, + Data_Store& issuer_info) const + { + std::multimap contents = + get_alt_name().contents(); + + if(oid_name_str == "X509v3.SubjectAlternativeName") + subject_info.add(contents); + else if(oid_name_str == "X509v3.IssuerAlternativeName") + issuer_info.add(contents); + else + throw Internal_Error("In Alternative_Name, unknown type " + + oid_name_str); + } + +/* +* Alternative_Name Constructor +*/ +Alternative_Name::Alternative_Name(const AlternativeName& alt_name, + const std::string& oid_name_str) + { + this->alt_name = alt_name; + this->oid_name_str = oid_name_str; + } + +/* +* Subject_Alternative_Name Constructor +*/ +Subject_Alternative_Name::Subject_Alternative_Name( + const AlternativeName& name) : + Alternative_Name(name, "X509v3.SubjectAlternativeName") + { + } + +/* +* Issuer_Alternative_Name Constructor +*/ +Issuer_Alternative_Name::Issuer_Alternative_Name(const AlternativeName& name) : + Alternative_Name(name, "X509v3.IssuerAlternativeName") + { + } + +/* +* Encode the extension +*/ +std::vector Extended_Key_Usage::encode_inner() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(oids) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void Extended_Key_Usage::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode_list(oids); + } + +/* +* Return a textual representation +*/ +void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + for(size_t i = 0; i != oids.size(); ++i) + subject.add("X509v3.ExtendedKeyUsage", oids[i].as_string()); + } + +namespace { + +/* +* A policy specifier +*/ +class Policy_Information : public ASN1_Object + { + public: + OID oid; + + Policy_Information() {} + Policy_Information(const OID& oid) : oid(oid) {} + + void encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .end_cons(); + } + + void decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .discard_remaining() + .end_cons(); + } + }; + +} + +/* +* Encode the extension +*/ +std::vector Certificate_Policies::encode_inner() const + { + std::vector policies; + + for(size_t i = 0; i != oids.size(); ++i) + policies.push_back(oids[i]); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(policies) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void Certificate_Policies::decode_inner(const std::vector& in) + { + std::vector policies; + + BER_Decoder(in).decode_list(policies); + + oids.clear(); + for(size_t i = 0; i != policies.size(); ++i) + oids.push_back(policies[i].oid); + } + +/* +* Return a textual representation +*/ +void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const + { + for(size_t i = 0; i != oids.size(); ++i) + info.add("X509v3.CertificatePolicies", oids[i].as_string()); + } + +std::vector Authority_Information_Access::encode_inner() const + { + ASN1_String url(m_ocsp_responder, IA5_STRING); + + return DER_Encoder() + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(OIDS::lookup("PKIX.OCSP")) + .add_object(ASN1_Tag(6), CONTEXT_SPECIFIC, url.iso_8859()) + .end_cons() + .end_cons().get_contents_unlocked(); + } + +void Authority_Information_Access::decode_inner(const std::vector& in) + { + BER_Decoder ber = BER_Decoder(in).start_cons(SEQUENCE); + + while(ber.more_items()) + { + OID oid; + + BER_Decoder info = ber.start_cons(SEQUENCE); + + info.decode(oid); + + if(oid == OIDS::lookup("PKIX.OCSP")) + { + BER_Object name = info.get_next_object(); + + if(name.type_tag == 6 && name.class_tag == CONTEXT_SPECIFIC) + { + m_ocsp_responder = Charset::transcode(ASN1::to_string(name), + LATIN1_CHARSET, + LOCAL_CHARSET); + } + + } + } + } + +void Authority_Information_Access::contents_to(Data_Store& subject, Data_Store&) const + { + if(m_ocsp_responder != "") + subject.add("OCSP.responder", m_ocsp_responder); + } + +/* +* Checked accessor for the crl_number member +*/ +size_t CRL_Number::get_crl_number() const + { + if(!has_value) + throw Invalid_State("CRL_Number::get_crl_number: Not set"); + return crl_number; + } + +/* +* Copy a CRL_Number extension +*/ +CRL_Number* CRL_Number::copy() const + { + if(!has_value) + throw Invalid_State("CRL_Number::copy: Not set"); + return new CRL_Number(crl_number); + } + +/* +* Encode the extension +*/ +std::vector CRL_Number::encode_inner() const + { + return DER_Encoder().encode(crl_number).get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void CRL_Number::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(crl_number); + } + +/* +* Return a textual representation +*/ +void CRL_Number::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLNumber", crl_number); + } + +/* +* Encode the extension +*/ +std::vector CRL_ReasonCode::encode_inner() const + { + return DER_Encoder() + .encode(static_cast(reason), ENUMERATED, UNIVERSAL) + .get_contents_unlocked(); + } + +/* +* Decode the extension +*/ +void CRL_ReasonCode::decode_inner(const std::vector& in) + { + size_t reason_code = 0; + BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL); + reason = static_cast(reason_code); + } + +/* +* Return a textual representation +*/ +void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLReasonCode", reason); + } + +std::vector CRL_Distribution_Points::encode_inner() const + { + throw std::runtime_error("CRL_Distribution_Points encoding not implemented"); + } + +void CRL_Distribution_Points::decode_inner(const std::vector& buf) + { + BER_Decoder(buf).decode_list(m_distribution_points).verify_end(); + } + +void CRL_Distribution_Points::contents_to(Data_Store& info, Data_Store&) const + { + for(size_t i = 0; i != m_distribution_points.size(); ++i) + { + auto point = m_distribution_points[i].point().contents(); + + auto uris = point.equal_range("URI"); + + for(auto uri = uris.first; uri != uris.second; ++uri) + info.add("CRL.DistributionPoint", uri->second); + } + } + +void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const + { + throw std::runtime_error("CRL_Distribution_Points encoding not implemented"); + } + +void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) + { + ber.start_cons(SEQUENCE) + .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC) + .decode_optional_implicit(m_point, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED), + SEQUENCE, CONSTRUCTED) + .end_cons().end_cons(); + } + +} + +} diff --git a/src/lib/cert/x509/x509_ext.h b/src/lib/cert/x509/x509_ext.h new file mode 100644 index 000000000..20be18a71 --- /dev/null +++ b/src/lib/cert/x509/x509_ext.h @@ -0,0 +1,388 @@ +/* +* X.509 Certificate Extensions +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_EXTENSIONS_H__ +#define BOTAN_X509_EXTENSIONS_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* X.509 Certificate Extension +*/ +class BOTAN_DLL Certificate_Extension + { + public: + /** + * @return OID representing this extension + */ + OID oid_of() const; + + /** + * Make a copy of this extension + * @return copy of this + */ + virtual Certificate_Extension* copy() const = 0; + + /* + * Add the contents of this extension into the information + * for the subject and/or issuer, as necessary. + * @param subject the subject info + * @param issuer the issuer info + */ + virtual void contents_to(Data_Store& subject, + Data_Store& issuer) const = 0; + + /* + * @return specific OID name + */ + virtual std::string oid_name() const = 0; + + virtual ~Certificate_Extension() {} + protected: + friend class Extensions; + virtual bool should_encode() const { return true; } + virtual std::vector encode_inner() const = 0; + virtual void decode_inner(const std::vector&) = 0; + }; + +/** +* X.509 Certificate Extension List +*/ +class BOTAN_DLL Extensions : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + void contents_to(Data_Store&, Data_Store&) const; + + void add(Certificate_Extension* extn, bool critical = false); + + Extensions& operator=(const Extensions&); + + Extensions(const Extensions&); + Extensions(bool st = true) : should_throw(st) {} + ~Extensions(); + private: + static Certificate_Extension* get_extension(const OID&); + + std::vector > extensions; + bool should_throw; + }; + +namespace Cert_Extension { + +static const size_t NO_CERT_PATH_LIMIT = 0xFFFFFFF0; + +/** +* Basic Constraints Extension +*/ +class BOTAN_DLL Basic_Constraints : public Certificate_Extension + { + public: + Basic_Constraints* copy() const + { return new Basic_Constraints(is_ca, path_limit); } + + Basic_Constraints(bool ca = false, size_t limit = 0) : + is_ca(ca), path_limit(limit) {} + + bool get_is_ca() const { return is_ca; } + size_t get_path_limit() const; + private: + std::string oid_name() const { return "X509v3.BasicConstraints"; } + + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + bool is_ca; + size_t path_limit; + }; + +/** +* Key Usage Constraints Extension +*/ +class BOTAN_DLL Key_Usage : public Certificate_Extension + { + public: + Key_Usage* copy() const { return new Key_Usage(constraints); } + + Key_Usage(Key_Constraints c = NO_CONSTRAINTS) : constraints(c) {} + + Key_Constraints get_constraints() const { return constraints; } + private: + std::string oid_name() const { return "X509v3.KeyUsage"; } + + bool should_encode() const { return (constraints != NO_CONSTRAINTS); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + Key_Constraints constraints; + }; + +/** +* Subject Key Identifier Extension +*/ +class BOTAN_DLL Subject_Key_ID : public Certificate_Extension + { + public: + Subject_Key_ID* copy() const { return new Subject_Key_ID(key_id); } + + Subject_Key_ID() {} + Subject_Key_ID(const std::vector&); + + std::vector get_key_id() const { return key_id; } + private: + std::string oid_name() const { return "X509v3.SubjectKeyIdentifier"; } + + bool should_encode() const { return (key_id.size() > 0); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector key_id; + }; + +/** +* Authority Key Identifier Extension +*/ +class BOTAN_DLL Authority_Key_ID : public Certificate_Extension + { + public: + Authority_Key_ID* copy() const { return new Authority_Key_ID(key_id); } + + Authority_Key_ID() {} + Authority_Key_ID(const std::vector& k) : key_id(k) {} + + std::vector get_key_id() const { return key_id; } + private: + std::string oid_name() const { return "X509v3.AuthorityKeyIdentifier"; } + + bool should_encode() const { return (key_id.size() > 0); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector key_id; + }; + +/** +* Alternative Name Extension Base Class +*/ +class BOTAN_DLL Alternative_Name : public Certificate_Extension + { + public: + AlternativeName get_alt_name() const { return alt_name; } + + protected: + Alternative_Name(const AlternativeName&, const std::string& oid_name); + + Alternative_Name(const std::string&, const std::string&); + private: + std::string oid_name() const { return oid_name_str; } + + bool should_encode() const { return alt_name.has_items(); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + std::string oid_name_str; + AlternativeName alt_name; + }; + +/** +* Subject Alternative Name Extension +*/ +class BOTAN_DLL Subject_Alternative_Name : public Alternative_Name + { + public: + Subject_Alternative_Name* copy() const + { return new Subject_Alternative_Name(get_alt_name()); } + + Subject_Alternative_Name(const AlternativeName& = AlternativeName()); + }; + +/** +* Issuer Alternative Name Extension +*/ +class BOTAN_DLL Issuer_Alternative_Name : public Alternative_Name + { + public: + Issuer_Alternative_Name* copy() const + { return new Issuer_Alternative_Name(get_alt_name()); } + + Issuer_Alternative_Name(const AlternativeName& = AlternativeName()); + }; + +/** +* Extended Key Usage Extension +*/ +class BOTAN_DLL Extended_Key_Usage : public Certificate_Extension + { + public: + Extended_Key_Usage* copy() const { return new Extended_Key_Usage(oids); } + + Extended_Key_Usage() {} + Extended_Key_Usage(const std::vector& o) : oids(o) {} + + std::vector get_oids() const { return oids; } + private: + std::string oid_name() const { return "X509v3.ExtendedKeyUsage"; } + + bool should_encode() const { return (oids.size() > 0); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector oids; + }; + +/** +* Certificate Policies Extension +*/ +class BOTAN_DLL Certificate_Policies : public Certificate_Extension + { + public: + Certificate_Policies* copy() const + { return new Certificate_Policies(oids); } + + Certificate_Policies() {} + Certificate_Policies(const std::vector& o) : oids(o) {} + + std::vector get_oids() const { return oids; } + private: + std::string oid_name() const { return "X509v3.CertificatePolicies"; } + + bool should_encode() const { return (oids.size() > 0); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector oids; + }; + +class BOTAN_DLL Authority_Information_Access : public Certificate_Extension + { + public: + Authority_Information_Access* copy() const + { return new Authority_Information_Access(m_ocsp_responder); } + + Authority_Information_Access() {} + + Authority_Information_Access(const std::string& ocsp) : + m_ocsp_responder(ocsp) {} + + private: + std::string oid_name() const { return "PKIX.AuthorityInformationAccess"; } + + bool should_encode() const { return (m_ocsp_responder != ""); } + + std::vector encode_inner() const; + void decode_inner(const std::vector&); + + void contents_to(Data_Store&, Data_Store&) const; + + std::string m_ocsp_responder; + }; + +/** +* CRL Number Extension +*/ +class BOTAN_DLL CRL_Number : public Certificate_Extension + { + public: + CRL_Number* copy() const; + + CRL_Number() : has_value(false), crl_number(0) {} + CRL_Number(size_t n) : has_value(true), crl_number(n) {} + + size_t get_crl_number() const; + private: + std::string oid_name() const { return "X509v3.CRLNumber"; } + + bool should_encode() const { return has_value; } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + bool has_value; + size_t crl_number; + }; + +/** +* CRL Entry Reason Code Extension +*/ +class BOTAN_DLL CRL_ReasonCode : public Certificate_Extension + { + public: + CRL_ReasonCode* copy() const { return new CRL_ReasonCode(reason); } + + CRL_ReasonCode(CRL_Code r = UNSPECIFIED) : reason(r) {} + + CRL_Code get_reason() const { return reason; } + private: + std::string oid_name() const { return "X509v3.ReasonCode"; } + + bool should_encode() const { return (reason != UNSPECIFIED); } + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + CRL_Code reason; + }; + +/** +* CRL Distribution Points Extension +*/ +class BOTAN_DLL CRL_Distribution_Points : public Certificate_Extension + { + public: + class BOTAN_DLL Distribution_Point : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + const AlternativeName& point() const { return m_point; } + private: + AlternativeName m_point; + }; + + CRL_Distribution_Points* copy() const + { return new CRL_Distribution_Points(m_distribution_points); } + + CRL_Distribution_Points() {} + + CRL_Distribution_Points(const std::vector& points) : + m_distribution_points(points) {} + + std::vector distribution_points() const + { return m_distribution_points; } + + private: + std::string oid_name() const { return "X509v3.CRLDistributionPoints"; } + + bool should_encode() const { return !m_distribution_points.empty(); } + + std::vector encode_inner() const; + void decode_inner(const std::vector&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector m_distribution_points; + }; + +} + +} + +#endif diff --git a/src/lib/cert/x509/x509_obj.cpp b/src/lib/cert/x509/x509_obj.cpp new file mode 100644 index 000000000..37d814ce6 --- /dev/null +++ b/src/lib/cert/x509/x509_obj.cpp @@ -0,0 +1,246 @@ +/* +* X.509 SIGNED Object +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create a generic X.509 object +*/ +X509_Object::X509_Object(DataSource& stream, const std::string& labels) + { + init(stream, labels); + } + +/* +* Create a generic X.509 object +*/ +X509_Object::X509_Object(const std::string& file, const std::string& labels) + { + DataSource_Stream stream(file, true); + init(stream, labels); + } + +/* +* Create a generic X.509 object +*/ +X509_Object::X509_Object(const std::vector& vec, const std::string& labels) + { + DataSource_Memory stream(&vec[0], vec.size()); + init(stream, labels); + } + +/* +* Read a PEM or BER X.509 object +*/ +void X509_Object::init(DataSource& in, const std::string& labels) + { + PEM_labels_allowed = split_on(labels, '/'); + if(PEM_labels_allowed.size() < 1) + throw Invalid_Argument("Bad labels argument to X509_Object"); + + PEM_label_pref = PEM_labels_allowed[0]; + std::sort(PEM_labels_allowed.begin(), PEM_labels_allowed.end()); + + try { + if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) + { + BER_Decoder dec(in); + decode_from(dec); + } + else + { + std::string got_label; + DataSource_Memory ber(PEM_Code::decode(in, got_label)); + + if(!std::binary_search(PEM_labels_allowed.begin(), + PEM_labels_allowed.end(), got_label)) + throw Decoding_Error("Invalid PEM label: " + got_label); + + BER_Decoder dec(ber); + decode_from(dec); + } + } + catch(Decoding_Error& e) + { + throw Decoding_Error(PEM_label_pref + " decoding failed: " + e.what()); + } + } + + +void X509_Object::encode_into(DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .end_cons() + .encode(sig_algo) + .encode(sig, BIT_STRING) + .end_cons(); + } + +/* +* Read a BER encoded X.509 object +*/ +void X509_Object::decode_from(BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .end_cons() + .decode(sig_algo) + .decode(sig, BIT_STRING) + .verify_end() + .end_cons(); + } + +/* +* Return a BER encoded X.509 object +*/ +std::vector X509_Object::BER_encode() const + { + DER_Encoder der; + encode_into(der); + return der.get_contents_unlocked(); + } + +/* +* Return a PEM encoded X.509 object +*/ +std::string X509_Object::PEM_encode() const + { + return PEM_Code::encode(BER_encode(), PEM_label_pref); + } + +/* +* Return the TBS data +*/ +std::vector X509_Object::tbs_data() const + { + return ASN1::put_in_sequence(tbs_bits); + } + +/* +* Return the signature of this object +*/ +std::vector X509_Object::signature() const + { + return sig; + } + +/* +* Return the algorithm used to sign this object +*/ +AlgorithmIdentifier X509_Object::signature_algorithm() const + { + return sig_algo; + } + +/* +* Return the hash used in generating the signature +*/ +std::string X509_Object::hash_used_for_signature() const + { + std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + if(sig_info.size() != 2) + throw Internal_Error("Invalid name format found for " + + sig_algo.oid.as_string()); + + std::vector pad_and_hash = + parse_algorithm_name(sig_info[1]); + + if(pad_and_hash.size() != 2) + throw Internal_Error("Invalid name format " + sig_info[1]); + + return pad_and_hash[1]; + } + +/* +* Check the signature on an object +*/ +bool X509_Object::check_signature(const Public_Key* pub_key) const + { + std::unique_ptr key(pub_key); + return check_signature(*key); + } + +/* +* Check the signature on an object +*/ +bool X509_Object::check_signature(const Public_Key& pub_key) const + { + try { + std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name()) + return false; + + std::string padding = sig_info[1]; + Signature_Format format = + (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + PK_Verifier verifier(pub_key, padding, format); + + return verifier.verify_message(tbs_data(), signature()); + } + catch(std::exception& e) + { + return false; + } + } + +/* +* Apply the X.509 SIGNED macro +*/ +std::vector X509_Object::make_signed(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& algo, + const secure_vector& tbs_bits) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .encode(algo) + .encode(signer->sign_message(tbs_bits, rng), BIT_STRING) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Try to decode the actual information +*/ +void X509_Object::do_decode() + { + try { + force_decode(); + } + catch(Decoding_Error& e) + { + throw Decoding_Error(PEM_label_pref + " decoding failed (" + + e.what() + ")"); + } + catch(Invalid_Argument& e) + { + throw Decoding_Error(PEM_label_pref + " decoding failed (" + + e.what() + ")"); + } + } + +} diff --git a/src/lib/cert/x509/x509_obj.h b/src/lib/cert/x509/x509_obj.h new file mode 100644 index 000000000..5905e1b37 --- /dev/null +++ b/src/lib/cert/x509/x509_obj.h @@ -0,0 +1,109 @@ +/* +* X.509 SIGNED Object +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_OBJECT_H__ +#define BOTAN_X509_OBJECT_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents abstract X.509 signed objects as +* in the X.500 SIGNED macro +*/ +class BOTAN_DLL X509_Object : public ASN1_Object + { + public: + /** + * The underlying data that is to be or was signed + * @return data that is or was signed + */ + std::vector tbs_data() const; + + /** + * @return signature on tbs_data() + */ + std::vector signature() const; + + /** + * @return signature algorithm that was used to generate signature + */ + AlgorithmIdentifier signature_algorithm() const; + + /** + * @return hash algorithm that was used to generate signature + */ + std::string hash_used_for_signature() const; + + /** + * Create a signed X509 object. + * @param signer the signer used to sign the object + * @param rng the random number generator to use + * @param alg_id the algorithm identifier of the signature scheme + * @param tbs the tbs bits to be signed + * @return signed X509 object + */ + static std::vector make_signed(class PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& alg_id, + const secure_vector& tbs); + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * @return true if the signature is valid, otherwise false + */ + bool check_signature(const Public_Key& key) const; + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * the pointer will be deleted after use + * @return true if the signature is valid, otherwise false + */ + bool check_signature(const Public_Key* key) const; + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + + /** + * @return BER encoding of this + */ + std::vector BER_encode() const; + + /** + * @return PEM encoding of this + */ + std::string PEM_encode() const; + + virtual ~X509_Object() {} + protected: + X509_Object(DataSource& src, const std::string& pem_labels); + X509_Object(const std::string& file, const std::string& pem_labels); + X509_Object(const std::vector& vec, const std::string& labels); + + void do_decode(); + X509_Object() {} + AlgorithmIdentifier sig_algo; + std::vector tbs_bits, sig; + private: + virtual void force_decode() = 0; + void init(DataSource&, const std::string&); + + std::vector PEM_labels_allowed; + std::string PEM_label_pref; + }; + +} + +#endif diff --git a/src/lib/cert/x509/x509cert.cpp b/src/lib/cert/x509/x509cert.cpp new file mode 100644 index 000000000..2362cd0cf --- /dev/null +++ b/src/lib/cert/x509/x509cert.cpp @@ -0,0 +1,587 @@ +/* +* X.509 Certificates +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Lookup each OID in the vector +*/ +std::vector lookup_oids(const std::vector& in) + { + std::vector out; + + for(auto i = in.begin(); i != in.end(); ++i) + out.push_back(OIDS::lookup(OID(*i))); + return out; + } + +} + +/* +* X509_Certificate Constructor +*/ +X509_Certificate::X509_Certificate(DataSource& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + self_signed = false; + do_decode(); + } + +/* +* X509_Certificate Constructor +*/ +X509_Certificate::X509_Certificate(const std::string& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + self_signed = false; + do_decode(); + } + +/* +* X509_Certificate Constructor +*/ +X509_Certificate::X509_Certificate(const std::vector& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + self_signed = false; + do_decode(); + } + +/* +* Decode the TBSCertificate data +*/ +void X509_Certificate::force_decode() + { + size_t version; + BigInt serial_bn; + AlgorithmIdentifier sig_algo_inner; + X509_DN dn_issuer, dn_subject; + X509_Time start, end; + + BER_Decoder tbs_cert(tbs_bits); + + tbs_cert.decode_optional(version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + .decode(serial_bn) + .decode(sig_algo_inner) + .decode(dn_issuer) + .start_cons(SEQUENCE) + .decode(start) + .decode(end) + .verify_end() + .end_cons() + .decode(dn_subject); + + if(version > 2) + throw Decoding_Error("Unknown X.509 cert version " + std::to_string(version)); + if(sig_algo != sig_algo_inner) + throw Decoding_Error("Algorithm identifier mismatch"); + + self_signed = (dn_subject == dn_issuer); + + subject.add(dn_subject.contents()); + issuer.add(dn_issuer.contents()); + + subject.add("X509.Certificate.dn_bits", ASN1::put_in_sequence(dn_subject.get_bits())); + issuer.add("X509.Certificate.dn_bits", ASN1::put_in_sequence(dn_issuer.get_bits())); + + BER_Object public_key = tbs_cert.get_next_object(); + if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED) + throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key", + public_key.type_tag, public_key.class_tag); + + std::vector v2_issuer_key_id, v2_subject_key_id; + + tbs_cert.decode_optional_string(v2_issuer_key_id, BIT_STRING, 1); + tbs_cert.decode_optional_string(v2_subject_key_id, BIT_STRING, 2); + + BER_Object v3_exts_data = tbs_cert.get_next_object(); + if(v3_exts_data.type_tag == 3 && + v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + Extensions extensions; + + BER_Decoder(v3_exts_data.value).decode(extensions).verify_end(); + + extensions.contents_to(subject, issuer); + } + else if(v3_exts_data.type_tag != NO_OBJECT) + throw BER_Bad_Tag("Unknown tag in X.509 cert", + v3_exts_data.type_tag, v3_exts_data.class_tag); + + if(tbs_cert.more_items()) + throw Decoding_Error("TBSCertificate has more items that expected"); + + subject.add("X509.Certificate.version", version); + subject.add("X509.Certificate.serial", BigInt::encode(serial_bn)); + subject.add("X509.Certificate.start", start.readable_string()); + subject.add("X509.Certificate.end", end.readable_string()); + + issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id); + subject.add("X509.Certificate.v2.key_id", v2_subject_key_id); + + subject.add("X509.Certificate.public_key", + hex_encode(public_key.value)); + + if(self_signed && version == 0) + { + subject.add("X509v3.BasicConstraints.is_ca", 1); + subject.add("X509v3.BasicConstraints.path_constraint", Cert_Extension::NO_CERT_PATH_LIMIT); + } + + if(is_CA_cert() && + !subject.has_value("X509v3.BasicConstraints.path_constraint")) + { + const size_t limit = (x509_version() < 3) ? + Cert_Extension::NO_CERT_PATH_LIMIT : 0; + + subject.add("X509v3.BasicConstraints.path_constraint", limit); + } + } + +/* +* Return the X.509 version in use +*/ +u32bit X509_Certificate::x509_version() const + { + return (subject.get1_u32bit("X509.Certificate.version") + 1); + } + +/* +* Return the time this cert becomes valid +*/ +std::string X509_Certificate::start_time() const + { + return subject.get1("X509.Certificate.start"); + } + +/* +* Return the time this cert becomes invalid +*/ +std::string X509_Certificate::end_time() const + { + return subject.get1("X509.Certificate.end"); + } + +/* +* Return information about the subject +*/ +std::vector +X509_Certificate::subject_info(const std::string& what) const + { + return subject.get(X509_DN::deref_info_field(what)); + } + +/* +* Return information about the issuer +*/ +std::vector +X509_Certificate::issuer_info(const std::string& what) const + { + return issuer.get(X509_DN::deref_info_field(what)); + } + +/* +* Return the public key in this certificate +*/ +Public_Key* X509_Certificate::subject_public_key() const + { + return X509::load_key( + ASN1::put_in_sequence(this->subject_public_key_bits())); + } + +std::vector X509_Certificate::subject_public_key_bits() const + { + return hex_decode(subject.get1("X509.Certificate.public_key")); + } + +/* +* Check if the certificate is for a CA +*/ +bool X509_Certificate::is_CA_cert() const + { + if(!subject.get1_u32bit("X509v3.BasicConstraints.is_ca")) + return false; + + return allowed_usage(KEY_CERT_SIGN); + } + +bool X509_Certificate::allowed_usage(Key_Constraints usage) const + { + if(constraints() == NO_CONSTRAINTS) + return true; + return (constraints() & usage); + } + +bool X509_Certificate::allowed_usage(const std::string& usage) const + { + for(auto constraint : ex_constraints()) + if(constraint == usage) + return true; + + return false; + } + +/* +* Return the path length constraint +*/ +u32bit X509_Certificate::path_limit() const + { + return subject.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0); + } + +/* +* Return the key usage constraints +*/ +Key_Constraints X509_Certificate::constraints() const + { + return Key_Constraints(subject.get1_u32bit("X509v3.KeyUsage", + NO_CONSTRAINTS)); + } + +/* +* Return the list of extended key usage OIDs +*/ +std::vector X509_Certificate::ex_constraints() const + { + return lookup_oids(subject.get("X509v3.ExtendedKeyUsage")); + } + +/* +* Return the list of certificate policies +*/ +std::vector X509_Certificate::policies() const + { + return lookup_oids(subject.get("X509v3.CertificatePolicies")); + } + +std::string X509_Certificate::ocsp_responder() const + { + return subject.get1("OCSP.responder", ""); + } + +std::string X509_Certificate::crl_distribution_point() const + { + return subject.get1("CRL.DistributionPoint", ""); + } + +/* +* Return the authority key id +*/ +std::vector X509_Certificate::authority_key_id() const + { + return issuer.get1_memvec("X509v3.AuthorityKeyIdentifier"); + } + +/* +* Return the subject key id +*/ +std::vector X509_Certificate::subject_key_id() const + { + return subject.get1_memvec("X509v3.SubjectKeyIdentifier"); + } + +/* +* Return the certificate serial number +*/ +std::vector X509_Certificate::serial_number() const + { + return subject.get1_memvec("X509.Certificate.serial"); + } + +/* +* Return the distinguished name of the issuer +*/ +X509_DN X509_Certificate::issuer_dn() const + { + return create_dn(issuer); + } + +std::vector X509_Certificate::raw_issuer_dn() const + { + return issuer.get1_memvec("X509.Certificate.dn_bits"); + } + +/* +* Return the distinguished name of the subject +*/ +X509_DN X509_Certificate::subject_dn() const + { + return create_dn(subject); + } + +std::vector X509_Certificate::raw_subject_dn() const + { + return subject.get1_memvec("X509.Certificate.dn_bits"); + } + +namespace { + +bool cert_subject_dns_match(const std::string& name, + const std::vector& cert_names) + { + for(size_t i = 0; i != cert_names.size(); ++i) + { + const std::string cn = cert_names[i]; + + if(cn == name) + return true; + + /* + * Possible wildcard match. We only support the most basic form of + * cert wildcarding ala RFC 2595 + */ + if(cn.size() > 2 && cn[0] == '*' && cn[1] == '.' && name.size() > cn.size()) + { + const std::string base = cn.substr(1, std::string::npos); + + if(name.compare(name.size() - base.size(), base.size(), base) == 0) + return true; + } + } + + return false; + } + +} + +std::string X509_Certificate::fingerprint(const std::string& hash_name) const + { + std::unique_ptr hash(get_hash(hash_name)); + hash->update(this->BER_encode()); + const auto hex_print = hex_encode(hash->final()); + + std::string formatted_print; + + for(size_t i = 0; i != hex_print.size(); i += 2) + { + formatted_print.push_back(hex_print[i]); + formatted_print.push_back(hex_print[i+1]); + + if(i != hex_print.size() - 2) + formatted_print.push_back(':'); + } + + return formatted_print; + } + +bool X509_Certificate::matches_dns_name(const std::string& name) const + { + if(name == "") + return false; + + if(cert_subject_dns_match(name, subject_info("DNS"))) + return true; + + if(cert_subject_dns_match(name, subject_info("Name"))) + return true; + + return false; + } + +/* +* Compare two certificates for equality +*/ +bool X509_Certificate::operator==(const X509_Certificate& other) const + { + return (sig == other.sig && + sig_algo == other.sig_algo && + self_signed == other.self_signed && + issuer == other.issuer && + subject == other.subject); + } + +bool X509_Certificate::operator<(const X509_Certificate& other) const + { + /* If signature values are not equal, sort by lexicographic ordering of that */ + if(sig != other.sig) + { + if(sig < other.sig) + return true; + return false; + } + + // Then compare the signed contents + return tbs_bits < other.tbs_bits; + } + +/* +* X.509 Certificate Comparison +*/ +bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2) + { + return !(cert1 == cert2); + } + +std::string X509_Certificate::to_string() const + { + const char* dn_fields[] = { "Name", + "Email", + "Organization", + "Organizational Unit", + "Locality", + "State", + "Country", + "IP", + "DNS", + "URI", + "PKIX.XMPPAddr", + nullptr }; + + std::ostringstream out; + + for(size_t i = 0; dn_fields[i]; ++i) + { + const std::vector vals = this->subject_info(dn_fields[i]); + + if(vals.empty()) + continue; + + out << "Subject " << dn_fields[i] << ":"; + for(size_t j = 0; j != vals.size(); ++j) + out << " " << vals[j]; + out << "\n"; + } + + for(size_t i = 0; dn_fields[i]; ++i) + { + const std::vector vals = this->issuer_info(dn_fields[i]); + + if(vals.empty()) + continue; + + out << "Issuer " << dn_fields[i] << ":"; + for(size_t j = 0; j != vals.size(); ++j) + out << " " << vals[j]; + out << "\n"; + } + + out << "Version: " << this->x509_version() << "\n"; + + out << "Not valid before: " << this->start_time() << "\n"; + out << "Not valid after: " << this->end_time() << "\n"; + + out << "Constraints:\n"; + Key_Constraints constraints = this->constraints(); + if(constraints == NO_CONSTRAINTS) + out << " None\n"; + else + { + if(constraints & DIGITAL_SIGNATURE) + out << " Digital Signature\n"; + if(constraints & NON_REPUDIATION) + out << " Non-Repuidation\n"; + if(constraints & KEY_ENCIPHERMENT) + out << " Key Encipherment\n"; + if(constraints & DATA_ENCIPHERMENT) + out << " Data Encipherment\n"; + if(constraints & KEY_AGREEMENT) + out << " Key Agreement\n"; + if(constraints & KEY_CERT_SIGN) + out << " Cert Sign\n"; + if(constraints & CRL_SIGN) + out << " CRL Sign\n"; + } + + std::vector policies = this->policies(); + if(!policies.empty()) + { + out << "Policies: " << "\n"; + for(size_t i = 0; i != policies.size(); i++) + out << " " << policies[i] << "\n"; + } + + std::vector ex_constraints = this->ex_constraints(); + if(!ex_constraints.empty()) + { + out << "Extended Constraints:\n"; + for(size_t i = 0; i != ex_constraints.size(); i++) + out << " " << ex_constraints[i] << "\n"; + } + + if(ocsp_responder() != "") + out << "OCSP responder " << ocsp_responder() << "\n"; + if(crl_distribution_point() != "") + out << "CRL " << crl_distribution_point() << "\n"; + + out << "Signature algorithm: " << + OIDS::lookup(this->signature_algorithm().oid) << "\n"; + + out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; + + if(this->authority_key_id().size()) + out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; + + if(this->subject_key_id().size()) + out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; + + std::unique_ptr pubkey(this->subject_public_key()); + out << "Public Key:\n" << X509::PEM_encode(*pubkey); + + return out.str(); + } + +/* +* Create and populate a X509_DN +*/ +X509_DN create_dn(const Data_Store& info) + { + auto names = info.search_for( + [](const std::string& key, const std::string&) + { + return (key.find("X520.") != std::string::npos); + }); + + X509_DN dn; + + for(auto i = names.begin(); i != names.end(); ++i) + dn.add_attribute(i->first, i->second); + + return dn; + } + +/* +* Create and populate an AlternativeName +*/ +AlternativeName create_alt_name(const Data_Store& info) + { + auto names = info.search_for( + [](const std::string& key, const std::string&) + { + return (key == "RFC822" || + key == "DNS" || + key == "URI" || + key == "IP"); + }); + + AlternativeName alt_name; + + for(auto i = names.begin(); i != names.end(); ++i) + alt_name.add_attribute(i->first, i->second); + + return alt_name; + } + +} diff --git a/src/lib/cert/x509/x509cert.h b/src/lib/cert/x509/x509cert.h new file mode 100644 index 000000000..bd341b6e0 --- /dev/null +++ b/src/lib/cert/x509/x509cert.h @@ -0,0 +1,249 @@ +/* +* X.509 Certificates +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_CERTS_H__ +#define BOTAN_X509_CERTS_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents X.509 Certificate +*/ +class BOTAN_DLL X509_Certificate : public X509_Object + { + public: + /** + * Get the public key associated with this certificate. + * @return subject public key of this certificate + */ + Public_Key* subject_public_key() const; + + /** + * Get the public key associated with this certificate. + * @return subject public key of this certificate + */ + std::vector subject_public_key_bits() const; + + /** + * Get the issuer certificate DN. + * @return issuer DN of this certificate + */ + X509_DN issuer_dn() const; + + /** + * Get the subject certificate DN. + * @return subject DN of this certificate + */ + X509_DN subject_dn() const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the paramter to look up. Possible names are + * "X509.Certificate.version", "X509.Certificate.serial", + * "X509.Certificate.start", "X509.Certificate.end", + * "X509.Certificate.v2.key_id", "X509.Certificate.public_key", + * "X509v3.BasicConstraints.path_constraint", + * "X509v3.BasicConstraints.is_ca", "X509v3.ExtendedKeyUsage", + * "X509v3.CertificatePolicies", "X509v3.SubjectKeyIdentifier" or + * "X509.Certificate.serial". + * @return value(s) of the specified parameter + */ + std::vector subject_info(const std::string& name) const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the paramter to look up. Possible names are + * "X509.Certificate.v2.key_id" or "X509v3.AuthorityKeyIdentifier". + * @return value(s) of the specified parameter + */ + std::vector issuer_info(const std::string& name) const; + + /** + * Raw subject DN + */ + std::vector raw_issuer_dn() const; + + /** + * Raw issuer DN + */ + std::vector raw_subject_dn() const; + + /** + * Get the notBefore of the certificate. + * @return notBefore of the certificate + */ + std::string start_time() const; + + /** + * Get the notAfter of the certificate. + * @return notAfter of the certificate + */ + std::string end_time() const; + + /** + * Get the X509 version of this certificate object. + * @return X509 version + */ + u32bit x509_version() const; + + /** + * Get the serial number of this certificate. + * @return certificates serial number + */ + std::vector serial_number() const; + + /** + * Get the DER encoded AuthorityKeyIdentifier of this certificate. + * @return DER encoded AuthorityKeyIdentifier + */ + std::vector authority_key_id() const; + + /** + * Get the DER encoded SubjectKeyIdentifier of this certificate. + * @return DER encoded SubjectKeyIdentifier + */ + std::vector subject_key_id() const; + + /** + * Check whether this certificate is self signed. + * @return true if this certificate is self signed + */ + bool is_self_signed() const { return self_signed; } + + /** + * Check whether this certificate is a CA certificate. + * @return true if this certificate is a CA certificate + */ + bool is_CA_cert() const; + + bool allowed_usage(Key_Constraints usage) const; + + /** + * Returns true if and only if name (referring to an extended key + * constraint, eg "PKIX.ServerAuth") is included in the extended + * key extension. + */ + bool allowed_usage(const std::string& usage) const; + + /** + * Get the path limit as defined in the BasicConstraints extension of + * this certificate. + * @return path limit + */ + u32bit path_limit() const; + + /** + * Get the key constraints as defined in the KeyUsage extension of this + * certificate. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the key constraints as defined in the ExtendedKeyUsage + * extension of this + * certificate. + * @return key constraints + */ + std::vector ex_constraints() const; + + /** + * Get the policies as defined in the CertificatePolicies extension + * of this certificate. + * @return certificate policies + */ + std::vector policies() const; + + /** + * Return the listed address of an OCSP responder, or empty if not set + */ + std::string ocsp_responder() const; + + /** + * Return the CRL distribution point, or empty if not set + */ + std::string crl_distribution_point() const; + + /** + * @return a string describing the certificate + */ + std::string to_string() const; + + /** + * Return a fingerprint of the certificate + */ + std::string fingerprint(const std::string& = "SHA-1") const; + + /** + * Check if a certain DNS name matches up with the information in + * the cert + */ + bool matches_dns_name(const std::string& name) const; + + /** + * Check to certificates for equality. + * @return true both certificates are (binary) equal + */ + bool operator==(const X509_Certificate& other) const; + + /** + * Impose an arbitrary (but consistent) ordering + * @return true if this is less than other by some unspecified criteria + */ + bool operator<(const X509_Certificate& other) const; + + /** + * Create a certificate from a data source providing the DER or + * PEM encoded certificate. + * @param source the data source + */ + X509_Certificate(DataSource& source); + + /** + * Create a certificate from a file containing the DER or PEM + * encoded certificate. + * @param filename the name of the certificate file + */ + X509_Certificate(const std::string& filename); + + X509_Certificate(const std::vector& in); + + private: + void force_decode(); + friend class X509_CA; + friend class BER_Decoder; + + X509_Certificate() {} + + Data_Store subject, issuer; + bool self_signed; + }; + +/** +* Check two certificates for inequality +* @return true if the arguments represent different certificates, +* false if they are binary identical +*/ +BOTAN_DLL bool operator!=(const X509_Certificate&, const X509_Certificate&); + +/* +* Data Store Extraction Operations +*/ +BOTAN_DLL X509_DN create_dn(const Data_Store&); +BOTAN_DLL AlternativeName create_alt_name(const Data_Store&); + +} + +#endif diff --git a/src/lib/cert/x509/x509opt.cpp b/src/lib/cert/x509/x509opt.cpp new file mode 100644 index 000000000..8a27fdbde --- /dev/null +++ b/src/lib/cert/x509/x509opt.cpp @@ -0,0 +1,107 @@ +/* +* X.509 Certificate Options +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Set when the certificate should become valid +*/ +void X509_Cert_Options::not_before(const std::string& time_string) + { + start = X509_Time(time_string); + } + +/* +* Set when the certificate should expire +*/ +void X509_Cert_Options::not_after(const std::string& time_string) + { + end = X509_Time(time_string); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_constraints(Key_Constraints usage) + { + constraints = usage; + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const OID& oid) + { + ex_constraints.push_back(oid); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const std::string& oid_str) + { + ex_constraints.push_back(OIDS::lookup(oid_str)); + } + +/* +* Mark this certificate for CA usage +*/ +void X509_Cert_Options::CA_key(size_t limit) + { + is_CA = true; + path_limit = limit; + } + +/* +* Do basic sanity checks +*/ +void X509_Cert_Options::sanity_check() const + { + if(common_name == "" || country == "") + throw Encoding_Error("X.509 certificate: name and country MUST be set"); + if(country.size() != 2) + throw Encoding_Error("Invalid ISO country code: " + country); + if(start >= end) + throw Encoding_Error("X509_Cert_Options: invalid time constraints"); + } + +/* +* Initialize the certificate options +*/ +X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, + u32bit expiration_time) + { + is_CA = false; + path_limit = 0; + constraints = NO_CONSTRAINTS; + + auto now = std::chrono::system_clock::now(); + + start = X509_Time(now); + end = X509_Time(now + std::chrono::seconds(expiration_time)); + + if(initial_opts == "") + return; + + std::vector parsed = split_on(initial_opts, '/'); + + if(parsed.size() > 4) + throw Invalid_Argument("X.509 cert options: Too many names: " + + initial_opts); + + if(parsed.size() >= 1) common_name = parsed[0]; + if(parsed.size() >= 2) country = parsed[1]; + if(parsed.size() >= 3) organization = parsed[2]; + if(parsed.size() == 4) org_unit = parsed[3]; + } + +} diff --git a/src/lib/cert/x509/x509path.cpp b/src/lib/cert/x509/x509path.cpp new file mode 100644 index 000000000..8c32d8f94 --- /dev/null +++ b/src/lib/cert/x509/x509path.cpp @@ -0,0 +1,360 @@ +/* +* X.509 Certificate Path Validation +* (C) 2010,2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const X509_Certificate* find_issuing_cert(const X509_Certificate& cert, + const std::vector& certstores) + { + const X509_DN issuer_dn = cert.issuer_dn(); + const std::vector auth_key_id = cert.authority_key_id(); + + for(size_t i = 0; i != certstores.size(); ++i) + { + if(const X509_Certificate* cert = certstores[i]->find_cert(issuer_dn, auth_key_id)) + return cert; + } + + return nullptr; + } + +const X509_CRL* find_crls_from(const X509_Certificate& cert, + const std::vector& certstores) + { + const X509_DN issuer_dn = cert.subject_dn(); + const std::vector auth_key_id = cert.subject_key_id(); + + for(size_t i = 0; i != certstores.size(); ++i) + { + if(const X509_CRL* crl = certstores[i]->find_crl(cert)) + return crl; + } + +#if 0 + const std::string crl_url = cert.crl_distribution_point(); + if(crl_url != "") + { + std::cout << "Downloading CRL " << crl_url << "\n"; + auto http = HTTP::GET_sync(crl_url); + + std::cout << http.status_message() << "\n"; + + http.throw_unless_ok(); + // check the mime type + + std::unique_ptr crl(new X509_CRL(http.body())); + + return crl.release(); + } +#endif + + return nullptr; + } + +Certificate_Status_Code check_chain(const std::vector& cert_path, + const Path_Validation_Restrictions& restrictions, + const std::vector& certstores) + { + const std::set& trusted_hashes = restrictions.trusted_hashes(); + + const bool self_signed_ee_cert = (cert_path.size() == 1); + + X509_Time current_time(std::chrono::system_clock::now()); + + std::vector> ocsp_responses; + + for(size_t i = 0; i != cert_path.size(); ++i) + { + const bool at_self_signed_root = (i == cert_path.size() - 1); + + const X509_Certificate& subject = cert_path[i]; + + const X509_Certificate& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; + + const Certificate_Store* trusted = certstores[0]; // fixme + + if(i == 0 || restrictions.ocsp_all_intermediates()) + ocsp_responses.push_back( + std::async(std::launch::async, + OCSP::online_check, issuer, subject, trusted)); + + // Check all certs for valid time range + if(current_time < X509_Time(subject.start_time())) + return Certificate_Status_Code::CERT_NOT_YET_VALID; + + if(current_time > X509_Time(subject.end_time())) + return Certificate_Status_Code::CERT_HAS_EXPIRED; + + // Check issuer constraints + + // Don't require CA bit set on self-signed end entity cert + if(!issuer.is_CA_cert() && !self_signed_ee_cert) + return Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER; + + if(issuer.path_limit() < i) + return Certificate_Status_Code::CERT_CHAIN_TOO_LONG; + + std::unique_ptr issuer_key(issuer.subject_public_key()); + + if(subject.check_signature(*issuer_key) == false) + return Certificate_Status_Code::SIGNATURE_ERROR; + + if(issuer_key->estimated_strength() < restrictions.minimum_key_strength()) + return Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK; + + if(!trusted_hashes.empty() && !at_self_signed_root) + if(!trusted_hashes.count(subject.hash_used_for_signature())) + return Certificate_Status_Code::UNTRUSTED_HASH; + } + + for(size_t i = 0; i != cert_path.size() - 1; ++i) + { + const X509_Certificate& subject = cert_path[i]; + const X509_Certificate& ca = cert_path[i+1]; + + if(i < ocsp_responses.size()) + { + try + { + OCSP::Response ocsp = ocsp_responses[i].get(); + + auto status = ocsp.status_for(ca, subject); + + if(status == CERT_IS_REVOKED) + return status; + + if(status == OCSP_RESPONSE_GOOD) + { + if(i == 0 && !restrictions.ocsp_all_intermediates()) + return status; // return immediately to just OCSP end cert + else + continue; + } + } + catch(std::exception& e) + { + } + } + + const X509_CRL* crl_p = find_crls_from(ca, certstores); + + if(!crl_p) + { + if(restrictions.require_revocation_information()) + return Certificate_Status_Code::NO_REVOCATION_DATA; + continue; + } + + const X509_CRL& crl = *crl_p; + + if(!ca.allowed_usage(CRL_SIGN)) + return Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER; + + if(current_time < X509_Time(crl.this_update())) + return Certificate_Status_Code::CRL_NOT_YET_VALID; + + if(current_time > X509_Time(crl.next_update())) + return Certificate_Status_Code::CRL_HAS_EXPIRED; + + if(crl.check_signature(ca.subject_public_key()) == false) + return Certificate_Status_Code::SIGNATURE_ERROR; + + if(crl.is_revoked(subject)) + return Certificate_Status_Code::CERT_IS_REVOKED; + } + + if(self_signed_ee_cert) + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + + return Certificate_Status_Code::VERIFIED; + } + +} + +Path_Validation_Result x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector& certstores) + { + if(end_certs.empty()) + throw std::invalid_argument("x509_path_validate called with no subjects"); + + std::vector cert_path = end_certs; + + // iterate until we reach a root or cannot find the issuer + while(!cert_path.back().is_self_signed()) + { + const X509_Certificate* cert = find_issuing_cert(cert_path.back(), certstores); + if(!cert) + return Path_Validation_Result(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND); + cert_path.push_back(*cert); + } + + Certificate_Status_Code res = check_chain(cert_path, restrictions, certstores); + + return Path_Validation_Result(res, std::move(cert_path)); + } + +Path_Validation_Result x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const std::vector& certstores) + { + std::vector certs; + certs.push_back(end_cert); + return x509_path_validate(certs, restrictions, certstores); + } + +Path_Validation_Result x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store) + { + std::vector certstores; + certstores.push_back(const_cast(&store)); + + return x509_path_validate(end_certs, restrictions, certstores); + } + +Path_Validation_Result x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store) + { + std::vector certs; + certs.push_back(end_cert); + + std::vector certstores; + certstores.push_back(const_cast(&store)); + + return x509_path_validate(certs, restrictions, certstores); + } + +Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, + size_t key_strength, + bool ocsp_all) : + m_require_revocation_information(require_rev), + m_ocsp_all_intermediates(ocsp_all), + m_minimum_key_strength(key_strength) + { + if(key_strength <= 80) + m_trusted_hashes.insert("SHA-160"); + + m_trusted_hashes.insert("SHA-224"); + m_trusted_hashes.insert("SHA-256"); + m_trusted_hashes.insert("SHA-384"); + m_trusted_hashes.insert("SHA-512"); + } + +const X509_Certificate& Path_Validation_Result::trust_root() const + { + return m_cert_path[m_cert_path.size()-1]; + } + +std::set Path_Validation_Result::trusted_hashes() const + { + std::set hashes; + for(size_t i = 0; i != m_cert_path.size(); ++i) + hashes.insert(m_cert_path[i].hash_used_for_signature()); + return hashes; + } + +bool Path_Validation_Result::successful_validation() const + { + if(status() == VERIFIED || status() == OCSP_RESPONSE_GOOD) + return true; + return false; + } + +std::string Path_Validation_Result::result_string() const + { + return status_string(m_status); + } + +std::string Path_Validation_Result::status_string(Certificate_Status_Code code) + { + switch(code) + { + case VERIFIED: + return "verified"; + case UNKNOWN_X509_ERROR: + return "unknown error"; + case CANNOT_ESTABLISH_TRUST: + return "cannot establish trust"; + case CERT_CHAIN_TOO_LONG: + return "certificate chain too long"; + case SIGNATURE_ERROR: + return "signature error"; + case SIGNATURE_METHOD_TOO_WEAK: + return "signature method too weak"; + + case POLICY_ERROR: + return "policy error"; + case INVALID_USAGE: + return "invalid usage"; + case UNTRUSTED_HASH: + return "untrusted hash function"; + + case CERT_MULTIPLE_ISSUERS_FOUND: + return "Multiple certificate issuers found"; + case CERT_FORMAT_ERROR: + return "Certificate format error"; + case CERT_ISSUER_NOT_FOUND: + return "Certificate issuer not found"; + case CERT_NOT_YET_VALID: + return "Certificate is not yet valid"; + case CERT_HAS_EXPIRED: + return "Certificate has expired"; + case CERT_IS_REVOKED: + return "Certificate is revoked"; + case NO_REVOCATION_DATA: + return "No revocation data available"; + case CRL_FORMAT_ERROR: + return "CRL format error"; + case CRL_NOT_YET_VALID: + return "CRL is not yet valid"; + case CRL_HAS_EXPIRED: + return "CRL has expired"; + case CRL_NOT_FOUND: + return "CRL not found"; + case CA_CERT_CANNOT_SIGN: + return "CA certificate cannot sign"; + case CA_CERT_NOT_FOR_CERT_ISSUER: + return "CA certificate not allowed to issue certs"; + case CA_CERT_NOT_FOR_CRL_ISSUER: + return "CA certificate not allowed to issue CRLs"; + + case OCSP_CERT_NOT_LISTED: + return "OCSP response does not included requested cert"; + case OCSP_NOT_YET_VALID: + return "OCSP response is from the future"; + case OCSP_EXPIRED: + return "OCSP response is expired"; + case OCSP_BAD_STATUS: + return "OCSP response had unknown/bad status"; + case OCSP_RESPONSE_GOOD: + return "OCSP response had good status"; + } + + // default case + return "Unknown code " + std::to_string(code); + } + +} diff --git a/src/lib/cert/x509/x509path.h b/src/lib/cert/x509/x509path.h new file mode 100644 index 000000000..d6a41a8f8 --- /dev/null +++ b/src/lib/cert/x509/x509path.h @@ -0,0 +1,165 @@ +/* +* X.509 Cert Path Validation +* (C) 2010-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_CERT_PATH_VALIDATION_H__ +#define BOTAN_X509_CERT_PATH_VALIDATION_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Specifies restrictions on the PKIX path validation +*/ +class BOTAN_DLL Path_Validation_Restrictions + { + public: + /** + * @param require_rev if true, revocation information is required + * @param minimum_key_strength is the minimum strength (in terms of + * operations, eg 80 means 2^80) of a signature. Signatures + * weaker than this are rejected. If more than 80, SHA-1 + * signatures are also rejected. + */ + Path_Validation_Restrictions(bool require_rev = false, + size_t minimum_key_strength = 80, + bool ocsp_all_intermediates = false); + + /** + * @param require_rev if true, revocation information is required + * @param minimum_key_strength is the minimum strength (in terms of + * operations, eg 80 means 2^80) of a signature. Signatures + * weaker than this are rejected. + * @param trusted_hashes a set of trusted hashes. Any signatures + * created using a hash other than one of these will be + * rejected. + */ + Path_Validation_Restrictions(bool require_rev, + size_t minimum_key_strength, + bool ocsp_all_intermediates, + const std::set& trusted_hashes) : + m_require_revocation_information(require_rev), + m_ocsp_all_intermediates(ocsp_all_intermediates), + m_trusted_hashes(trusted_hashes), + m_minimum_key_strength(minimum_key_strength) {} + + bool require_revocation_information() const + { return m_require_revocation_information; } + + bool ocsp_all_intermediates() const + { return m_ocsp_all_intermediates; } + + const std::set& trusted_hashes() const + { return m_trusted_hashes; } + + size_t minimum_key_strength() const + { return m_minimum_key_strength; } + + private: + bool m_require_revocation_information; + bool m_ocsp_all_intermediates; + std::set m_trusted_hashes; + size_t m_minimum_key_strength; + }; + +/** +* Represents the result of a PKIX path validation +*/ +class BOTAN_DLL Path_Validation_Result + { + public: + typedef Certificate_Status_Code Code; + + /** + * @return the set of hash functions you are implicitly + * trusting by trusting this result. + */ + std::set trusted_hashes() const; + + /** + * @return the trust root of the validation + */ + const X509_Certificate& trust_root() const; + + /** + * @return the full path from subject to trust root + */ + const std::vector& cert_path() const { return m_cert_path; } + + /** + * @return true iff the validation was succesful + */ + bool successful_validation() const; + + /** + * @return validation result code + */ + Certificate_Status_Code result() const { return m_status; } + + Certificate_Status_Code status() const { return m_status; } + + /** + * @return string representation of the validation result + */ + std::string result_string() const; + + static std::string status_string(Certificate_Status_Code code); + + Path_Validation_Result(Certificate_Status_Code status, + std::vector&& cert_chain) : + m_status(status), m_cert_path(cert_chain) {} + + Path_Validation_Result(Certificate_Status_Code status) : m_status(status) {} + + private: + friend Path_Validation_Result x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector& certstores); + + Certificate_Status_Code m_status; + std::vector m_cert_path; + }; + +/** +* PKIX Path Validation +*/ +Path_Validation_Result BOTAN_DLL x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector& certstores); + +/** +* PKIX Path Validation +*/ +Path_Validation_Result BOTAN_DLL x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const std::vector& certstores); + +/** +* PKIX Path Validation +*/ +Path_Validation_Result BOTAN_DLL x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store); + +/** +* PKIX Path Validation +*/ +Path_Validation_Result BOTAN_DLL x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store); + +} + +#endif diff --git a/src/lib/cert/x509/x509self.cpp b/src/lib/cert/x509/x509self.cpp new file mode 100644 index 000000000..c13772382 --- /dev/null +++ b/src/lib/cert/x509/x509self.cpp @@ -0,0 +1,163 @@ +/* +* PKCS #10/Self Signed Cert Creation +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Load information from the X509_Cert_Options +*/ +void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn, + AlternativeName& subject_alt) + { + subject_dn.add_attribute("X520.CommonName", opts.common_name); + subject_dn.add_attribute("X520.Country", opts.country); + subject_dn.add_attribute("X520.State", opts.state); + subject_dn.add_attribute("X520.Locality", opts.locality); + subject_dn.add_attribute("X520.Organization", opts.organization); + subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit); + subject_dn.add_attribute("X520.SerialNumber", opts.serial_number); + subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip); + subject_alt.add_othername(OIDS::lookup("PKIX.XMPPAddr"), + opts.xmpp, UTF8_STRING); + } + +} + +namespace X509 { + +/* +* Create a new self-signed X.509 certificate +*/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + opts.sanity_check(); + + std::vector pub_key = X509::BER_encode(key); + std::unique_ptr signer(choose_sig_format(key, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + Key_Constraints constraints; + if(opts.is_CA) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + constraints = find_constraints(key, opts.constraints); + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), + true); + + extensions.add(new Cert_Extension::Key_Usage(constraints), true); + + extensions.add(new Cert_Extension::Subject_Key_ID(pub_key)); + + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + + return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key, + opts.start, opts.end, + subject_dn, subject_dn, + extensions); + } + +/* +* Create a PKCS #10 certificate request +*/ +PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + opts.sanity_check(); + + std::vector pub_key = X509::BER_encode(key); + std::unique_ptr signer(choose_sig_format(key, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + const size_t PKCS10_VERSION = 0; + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); + extensions.add( + new Cert_Extension::Key_Usage( + opts.is_CA ? Key_Constraints(KEY_CERT_SIGN | CRL_SIGN) : + find_constraints(key, opts.constraints) + ) + ); + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + DER_Encoder tbs_req; + + tbs_req.start_cons(SEQUENCE) + .encode(PKCS10_VERSION) + .encode(subject_dn) + .raw_bytes(pub_key) + .start_explicit(0); + + if(opts.challenge != "") + { + ASN1_String challenge(opts.challenge, DIRECTORY_STRING); + + tbs_req.encode( + Attribute("PKCS9.ChallengePassword", + DER_Encoder().encode(challenge).get_contents_unlocked() + ) + ); + } + + tbs_req.encode( + Attribute("PKCS9.ExtensionRequest", + DER_Encoder() + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .get_contents_unlocked() + ) + ) + .end_explicit() + .end_cons(); + + const std::vector req = + X509_Object::make_signed(signer.get(), rng, sig_algo, + tbs_req.get_contents()); + + return PKCS10_Request(req); + } + +} + +} diff --git a/src/lib/cert/x509/x509self.h b/src/lib/cert/x509/x509self.h new file mode 100644 index 000000000..eee4d10c6 --- /dev/null +++ b/src/lib/cert/x509/x509self.h @@ -0,0 +1,203 @@ +/* +* X.509 Self-Signed Certificate +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_SELF_H__ +#define BOTAN_X509_SELF_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Options for X.509 certificates. +*/ +class BOTAN_DLL X509_Cert_Options + { + public: + /** + * the subject common name + */ + std::string common_name; + + /** + * the subject counry + */ + std::string country; + + /** + * the subject organization + */ + std::string organization; + + /** + * the subject organizational unit + */ + std::string org_unit; + + /** + * the subject locality + */ + std::string locality; + + /** + * the subject state + */ + std::string state; + + /** + * the subject serial number + */ + std::string serial_number; + + /** + * the subject email adress + */ + std::string email; + + /** + * the subject URI + */ + std::string uri; + + /** + * the subject IPv4 address + */ + std::string ip; + + /** + * the subject DNS + */ + std::string dns; + + /** + * the subject XMPP + */ + std::string xmpp; + + /** + * the subject challenge password + */ + std::string challenge; + + /** + * the subject notBefore + */ + X509_Time start; + /** + * the subject notAfter + */ + X509_Time end; + + /** + * Indicates whether the certificate request + */ + bool is_CA; + + /** + * Indicates the BasicConstraints path limit + */ + size_t path_limit; + + /** + * The key constraints for the subject public key + */ + Key_Constraints constraints; + + /** + * The key extended constraints for the subject public key + */ + std::vector ex_constraints; + + /** + * Check the options set in this object for validity. + */ + void sanity_check() const; + + /** + * Mark the certificate as a CA certificate and set the path limit. + * @param limit the path limit to be set in the BasicConstraints extension. + */ + void CA_key(size_t limit = 1); + + /** + * Set the notBefore of the certificate. + * @param time the notBefore value of the certificate + */ + void not_before(const std::string& time); + + /** + * Set the notAfter of the certificate. + * @param time the notAfter value of the certificate + */ + void not_after(const std::string& time); + + /** + * Add the key constraints of the KeyUsage extension. + * @param constr the constraints to set + */ + void add_constraints(Key_Constraints constr); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param oid the oid to add + */ + void add_ex_constraint(const OID& oid); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param name the name to look up the oid to add + */ + void add_ex_constraint(const std::string& name); + + /** + * Construct a new options object + * @param opts define the common name of this object. An example for this + * parameter would be "common_name/country/organization/organizational_unit". + * @param expire_time the expiration time (from the current clock in seconds) + */ + X509_Cert_Options(const std::string& opts = "", + u32bit expire_time = 365 * 24 * 60 * 60); + }; + +namespace X509 { + +/** +* Create a self-signed X.509 certificate. +* @param opts the options defining the certificate to create +* @param key the private key used for signing, i.e. the key +* associated with this self-signed certificate +* @param hash_fn the hash function to use +* @param rng the rng to use +* @return newly created self-signed certificate +*/ +BOTAN_DLL X509_Certificate +create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +/** +* Create a PKCS#10 certificate request. +* @param opts the options defining the request to create +* @param key the key used to sign this request +* @param rng the rng to use +* @param hash_fn the hash function to use +* @return newly created PKCS#10 request +*/ +BOTAN_DLL PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +} + +} + +#endif diff --git a/src/lib/checksum/adler32/adler32.cpp b/src/lib/checksum/adler32/adler32.cpp new file mode 100644 index 000000000..62589733f --- /dev/null +++ b/src/lib/checksum/adler32/adler32.cpp @@ -0,0 +1,81 @@ +/* +* Adler32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +void adler32_update(const byte input[], size_t length, + u16bit& S1, u16bit& S2) + { + u32bit S1x = S1; + u32bit S2x = S2; + + while(length >= 16) + { + S1x += input[ 0]; S2x += S1x; + S1x += input[ 1]; S2x += S1x; + S1x += input[ 2]; S2x += S1x; + S1x += input[ 3]; S2x += S1x; + S1x += input[ 4]; S2x += S1x; + S1x += input[ 5]; S2x += S1x; + S1x += input[ 6]; S2x += S1x; + S1x += input[ 7]; S2x += S1x; + S1x += input[ 8]; S2x += S1x; + S1x += input[ 9]; S2x += S1x; + S1x += input[10]; S2x += S1x; + S1x += input[11]; S2x += S1x; + S1x += input[12]; S2x += S1x; + S1x += input[13]; S2x += S1x; + S1x += input[14]; S2x += S1x; + S1x += input[15]; S2x += S1x; + input += 16; + length -= 16; + } + + for(size_t j = 0; j != length; ++j) + { + S1x += input[j]; + S2x += S1x; + } + + S1 = S1x % 65521; + S2 = S2x % 65521; + } + +} + +/* +* Update an Adler32 Checksum +*/ +void Adler32::add_data(const byte input[], size_t length) + { + const size_t PROCESS_AMOUNT = 5552; + + while(length >= PROCESS_AMOUNT) + { + adler32_update(input, PROCESS_AMOUNT, S1, S2); + input += PROCESS_AMOUNT; + length -= PROCESS_AMOUNT; + } + + adler32_update(input, length, S1, S2); + } + +/* +* Finalize an Adler32 Checksum +*/ +void Adler32::final_result(byte output[]) + { + store_be(output, S2, S1); + clear(); + } + +} diff --git a/src/lib/checksum/adler32/adler32.h b/src/lib/checksum/adler32/adler32.h new file mode 100644 index 000000000..dc2872ca1 --- /dev/null +++ b/src/lib/checksum/adler32/adler32.h @@ -0,0 +1,37 @@ +/* +* Adler32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ADLER32_H__ +#define BOTAN_ADLER32_H__ + +#include + +namespace Botan { + +/** +* The Adler32 checksum, used in zlib +*/ +class BOTAN_DLL Adler32 : public HashFunction + { + public: + std::string name() const { return "Adler32"; } + size_t output_length() const { return 4; } + HashFunction* clone() const { return new Adler32; } + + void clear() { S1 = 1; S2 = 0; } + + Adler32() { clear(); } + ~Adler32() { clear(); } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + u16bit S1, S2; + }; + +} + +#endif diff --git a/src/lib/checksum/adler32/info.txt b/src/lib/checksum/adler32/info.txt new file mode 100644 index 000000000..6744fbee4 --- /dev/null +++ b/src/lib/checksum/adler32/info.txt @@ -0,0 +1,5 @@ +define ADLER32 20131128 + + +hash + diff --git a/src/lib/checksum/crc24/crc24.cpp b/src/lib/checksum/crc24/crc24.cpp new file mode 100644 index 000000000..d641047a2 --- /dev/null +++ b/src/lib/checksum/crc24/crc24.cpp @@ -0,0 +1,102 @@ +/* +* CRC24 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Update a CRC24 Checksum +*/ +void CRC24::add_data(const byte input[], size_t length) + { + const u32bit TABLE[256] = { + 0x00000000, 0x00864CFB, 0x008AD50D, 0x000C99F6, 0x0093E6E1, 0x0015AA1A, + 0x001933EC, 0x009F7F17, 0x00A18139, 0x0027CDC2, 0x002B5434, 0x00AD18CF, + 0x003267D8, 0x00B42B23, 0x00B8B2D5, 0x003EFE2E, 0x00C54E89, 0x00430272, + 0x004F9B84, 0x00C9D77F, 0x0056A868, 0x00D0E493, 0x00DC7D65, 0x005A319E, + 0x0064CFB0, 0x00E2834B, 0x00EE1ABD, 0x00685646, 0x00F72951, 0x007165AA, + 0x007DFC5C, 0x00FBB0A7, 0x000CD1E9, 0x008A9D12, 0x008604E4, 0x0000481F, + 0x009F3708, 0x00197BF3, 0x0015E205, 0x0093AEFE, 0x00AD50D0, 0x002B1C2B, + 0x002785DD, 0x00A1C926, 0x003EB631, 0x00B8FACA, 0x00B4633C, 0x00322FC7, + 0x00C99F60, 0x004FD39B, 0x00434A6D, 0x00C50696, 0x005A7981, 0x00DC357A, + 0x00D0AC8C, 0x0056E077, 0x00681E59, 0x00EE52A2, 0x00E2CB54, 0x006487AF, + 0x00FBF8B8, 0x007DB443, 0x00712DB5, 0x00F7614E, 0x0019A3D2, 0x009FEF29, + 0x009376DF, 0x00153A24, 0x008A4533, 0x000C09C8, 0x0000903E, 0x0086DCC5, + 0x00B822EB, 0x003E6E10, 0x0032F7E6, 0x00B4BB1D, 0x002BC40A, 0x00AD88F1, + 0x00A11107, 0x00275DFC, 0x00DCED5B, 0x005AA1A0, 0x00563856, 0x00D074AD, + 0x004F0BBA, 0x00C94741, 0x00C5DEB7, 0x0043924C, 0x007D6C62, 0x00FB2099, + 0x00F7B96F, 0x0071F594, 0x00EE8A83, 0x0068C678, 0x00645F8E, 0x00E21375, + 0x0015723B, 0x00933EC0, 0x009FA736, 0x0019EBCD, 0x008694DA, 0x0000D821, + 0x000C41D7, 0x008A0D2C, 0x00B4F302, 0x0032BFF9, 0x003E260F, 0x00B86AF4, + 0x002715E3, 0x00A15918, 0x00ADC0EE, 0x002B8C15, 0x00D03CB2, 0x00567049, + 0x005AE9BF, 0x00DCA544, 0x0043DA53, 0x00C596A8, 0x00C90F5E, 0x004F43A5, + 0x0071BD8B, 0x00F7F170, 0x00FB6886, 0x007D247D, 0x00E25B6A, 0x00641791, + 0x00688E67, 0x00EEC29C, 0x003347A4, 0x00B50B5F, 0x00B992A9, 0x003FDE52, + 0x00A0A145, 0x0026EDBE, 0x002A7448, 0x00AC38B3, 0x0092C69D, 0x00148A66, + 0x00181390, 0x009E5F6B, 0x0001207C, 0x00876C87, 0x008BF571, 0x000DB98A, + 0x00F6092D, 0x007045D6, 0x007CDC20, 0x00FA90DB, 0x0065EFCC, 0x00E3A337, + 0x00EF3AC1, 0x0069763A, 0x00578814, 0x00D1C4EF, 0x00DD5D19, 0x005B11E2, + 0x00C46EF5, 0x0042220E, 0x004EBBF8, 0x00C8F703, 0x003F964D, 0x00B9DAB6, + 0x00B54340, 0x00330FBB, 0x00AC70AC, 0x002A3C57, 0x0026A5A1, 0x00A0E95A, + 0x009E1774, 0x00185B8F, 0x0014C279, 0x00928E82, 0x000DF195, 0x008BBD6E, + 0x00872498, 0x00016863, 0x00FAD8C4, 0x007C943F, 0x00700DC9, 0x00F64132, + 0x00693E25, 0x00EF72DE, 0x00E3EB28, 0x0065A7D3, 0x005B59FD, 0x00DD1506, + 0x00D18CF0, 0x0057C00B, 0x00C8BF1C, 0x004EF3E7, 0x00426A11, 0x00C426EA, + 0x002AE476, 0x00ACA88D, 0x00A0317B, 0x00267D80, 0x00B90297, 0x003F4E6C, + 0x0033D79A, 0x00B59B61, 0x008B654F, 0x000D29B4, 0x0001B042, 0x0087FCB9, + 0x001883AE, 0x009ECF55, 0x009256A3, 0x00141A58, 0x00EFAAFF, 0x0069E604, + 0x00657FF2, 0x00E33309, 0x007C4C1E, 0x00FA00E5, 0x00F69913, 0x0070D5E8, + 0x004E2BC6, 0x00C8673D, 0x00C4FECB, 0x0042B230, 0x00DDCD27, 0x005B81DC, + 0x0057182A, 0x00D154D1, 0x0026359F, 0x00A07964, 0x00ACE092, 0x002AAC69, + 0x00B5D37E, 0x00339F85, 0x003F0673, 0x00B94A88, 0x0087B4A6, 0x0001F85D, + 0x000D61AB, 0x008B2D50, 0x00145247, 0x00921EBC, 0x009E874A, 0x0018CBB1, + 0x00E37B16, 0x006537ED, 0x0069AE1B, 0x00EFE2E0, 0x00709DF7, 0x00F6D10C, + 0x00FA48FA, 0x007C0401, 0x0042FA2F, 0x00C4B6D4, 0x00C82F22, 0x004E63D9, + 0x00D11CCE, 0x00575035, 0x005BC9C3, 0x00DD8538 }; + + u32bit tmp = crc; + while(length >= 16) + { + tmp = TABLE[((tmp >> 16) ^ input[ 0]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 1]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 2]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 3]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 4]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 5]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 6]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 7]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 8]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 9]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[10]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[11]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[12]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[13]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[14]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[15]) & 0xFF] ^ (tmp << 8); + input += 16; + length -= 16; + } + + for(size_t i = 0; i != length; ++i) + tmp = TABLE[((tmp >> 16) ^ input[i]) & 0xFF] ^ (tmp << 8); + + crc = tmp; + } + +/* +* Finalize a CRC24 Checksum +*/ +void CRC24::final_result(byte output[]) + { + for(size_t i = 0; i != 3; ++i) + output[i] = get_byte(i+1, crc); + clear(); + } + +} diff --git a/src/lib/checksum/crc24/crc24.h b/src/lib/checksum/crc24/crc24.h new file mode 100644 index 000000000..b5faebcee --- /dev/null +++ b/src/lib/checksum/crc24/crc24.h @@ -0,0 +1,37 @@ +/* +* CRC24 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CRC24_H__ +#define BOTAN_CRC24_H__ + +#include + +namespace Botan { + +/** +* 24-bit cyclic redundancy check +*/ +class BOTAN_DLL CRC24 : public HashFunction + { + public: + std::string name() const { return "CRC24"; } + size_t output_length() const { return 3; } + HashFunction* clone() const { return new CRC24; } + + void clear() { crc = 0xB704CE; } + + CRC24() { clear(); } + ~CRC24() { clear(); } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + u32bit crc; + }; + +} + +#endif diff --git a/src/lib/checksum/crc24/info.txt b/src/lib/checksum/crc24/info.txt new file mode 100644 index 000000000..f3762c66f --- /dev/null +++ b/src/lib/checksum/crc24/info.txt @@ -0,0 +1,5 @@ +define CRC24 20131128 + + +hash + diff --git a/src/lib/checksum/crc32/crc32.cpp b/src/lib/checksum/crc32/crc32.cpp new file mode 100644 index 000000000..574e13bae --- /dev/null +++ b/src/lib/checksum/crc32/crc32.cpp @@ -0,0 +1,102 @@ +/* +* CRC32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Update a CRC32 Checksum +*/ +void CRC32::add_data(const byte input[], size_t length) + { + const u32bit TABLE[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; + + u32bit tmp = crc; + while(length >= 16) + { + tmp = TABLE[(tmp ^ input[ 0]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 1]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 2]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 3]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 4]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 5]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 6]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 7]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 8]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 9]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[10]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[11]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[12]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[13]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[14]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[15]) & 0xFF] ^ (tmp >> 8); + input += 16; + length -= 16; + } + + for(size_t i = 0; i != length; ++i) + tmp = TABLE[(tmp ^ input[i]) & 0xFF] ^ (tmp >> 8); + + crc = tmp; + } + +/* +* Finalize a CRC32 Checksum +*/ +void CRC32::final_result(byte output[]) + { + crc ^= 0xFFFFFFFF; + store_be(crc, output); + clear(); + } + +} diff --git a/src/lib/checksum/crc32/crc32.h b/src/lib/checksum/crc32/crc32.h new file mode 100644 index 000000000..dec3d0449 --- /dev/null +++ b/src/lib/checksum/crc32/crc32.h @@ -0,0 +1,37 @@ +/* +* CRC32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CRC32_H__ +#define BOTAN_CRC32_H__ + +#include + +namespace Botan { + +/** +* 32-bit cyclic redundancy check +*/ +class BOTAN_DLL CRC32 : public HashFunction + { + public: + std::string name() const { return "CRC32"; } + size_t output_length() const { return 4; } + HashFunction* clone() const { return new CRC32; } + + void clear() { crc = 0xFFFFFFFF; } + + CRC32() { clear(); } + ~CRC32() { clear(); } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + u32bit crc; + }; + +} + +#endif diff --git a/src/lib/checksum/crc32/info.txt b/src/lib/checksum/crc32/info.txt new file mode 100644 index 000000000..c7275ab43 --- /dev/null +++ b/src/lib/checksum/crc32/info.txt @@ -0,0 +1,5 @@ +define CRC32 20131128 + + +hash + diff --git a/src/lib/codec/base64/base64.cpp b/src/lib/codec/base64/base64.cpp new file mode 100644 index 000000000..b66478d2b --- /dev/null +++ b/src/lib/codec/base64/base64.cpp @@ -0,0 +1,245 @@ +/* +* Base64 Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +static const byte BIN_TO_BASE64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +void do_base64_encode(char out[4], const byte in[3]) + { + out[0] = BIN_TO_BASE64[((in[0] & 0xFC) >> 2)]; + out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)]; + out[3] = BIN_TO_BASE64[((in[2] & 0x3F) )]; + } + +} + +size_t base64_encode(char out[], + const byte in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + input_consumed = 0; + + size_t input_remaining = input_length; + size_t output_produced = 0; + + while(input_remaining >= 3) + { + do_base64_encode(out + output_produced, in + input_consumed); + + input_consumed += 3; + output_produced += 4; + input_remaining -= 3; + } + + if(final_inputs && input_remaining) + { + byte remainder[3] = { 0 }; + for(size_t i = 0; i != input_remaining; ++i) + remainder[i] = in[input_consumed + i]; + + do_base64_encode(out + output_produced, remainder); + + size_t empty_bits = 8 * (3 - input_remaining); + size_t index = output_produced + 4 - 1; + while(empty_bits >= 8) + { + out[index--] = '='; + empty_bits -= 6; + } + + input_consumed += input_remaining; + output_produced += 4; + } + + return output_produced; + } + +std::string base64_encode(const byte input[], + size_t input_length) + { + std::string output((round_up(input_length, 3) / 3) * 4, 0); + + size_t consumed = 0; + size_t produced = base64_encode(&output[0], + input, input_length, + consumed, true); + + BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); + BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); + + return output; + } + +size_t base64_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws) + { + /* + * Base64 Decoder Lookup Table + * Warning: assumes ASCII encodings + */ + static const byte BASE64_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, + 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + byte* out_ptr = output; + byte decode_buf[4]; + size_t decode_buf_pos = 0; + size_t final_truncate = 0; + + clear_mem(output, input_length * 3 / 4); + + for(size_t i = 0; i != input_length; ++i) + { + const byte bin = BASE64_TO_BIN[static_cast(input[i])]; + + if(bin <= 0x3F) + { + decode_buf[decode_buf_pos] = bin; + decode_buf_pos += 1; + } + else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) + { + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + else if(bad_char == "\r") + bad_char = "\\r"; + + throw std::invalid_argument( + std::string("base64_decode: invalid base64 character '") + + bad_char + "'"); + } + + /* + * If we're at the end of the input, pad with 0s and truncate + */ + if(final_inputs && (i == input_length - 1)) + { + if(decode_buf_pos) + { + for(size_t i = decode_buf_pos; i != 4; ++i) + decode_buf[i] = 0; + final_truncate = (4 - decode_buf_pos); + decode_buf_pos = 4; + } + } + + if(decode_buf_pos == 4) + { + out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); + out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); + out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; + + out_ptr += 3; + decode_buf_pos = 0; + input_consumed = i+1; + } + } + + while(input_consumed < input_length && + BASE64_TO_BIN[static_cast(input[input_consumed])] == 0x80) + { + ++input_consumed; + } + + size_t written = (out_ptr - output) - final_truncate; + + return written; + } + +size_t base64_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = base64_decode(output, input, input_length, + consumed, true, ignore_ws); + + if(consumed != input_length) + throw std::invalid_argument("base64_decode: input did not have full bytes"); + + return written; + } + +size_t base64_decode(byte output[], + const std::string& input, + bool ignore_ws) + { + return base64_decode(output, &input[0], input.length(), ignore_ws); + } + +secure_vector base64_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + secure_vector bin((round_up(input_length, 4) * 3) / 4); + + size_t written = base64_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +secure_vector base64_decode(const std::string& input, + bool ignore_ws) + { + return base64_decode(&input[0], input.size(), ignore_ws); + } + + +} diff --git a/src/lib/codec/base64/base64.h b/src/lib/codec/base64/base64.h new file mode 100644 index 000000000..9ea4143b7 --- /dev/null +++ b/src/lib/codec/base64/base64.h @@ -0,0 +1,127 @@ +/* +* Base64 Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BASE64_CODEC_H__ +#define BOTAN_BASE64_CODEC_H__ + +#include +#include + +namespace Botan { + +/** +* Perform base64 encoding +* @param output an array of at least input_length*4/3 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_encode(char output[], + const byte input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs); + +/** +* Perform base64 encoding +* @param input some input +* @param input_length length of input in bytes +* @return base64adecimal representation of input +*/ +std::string BOTAN_DLL base64_encode(const byte input[], + size_t input_length); + +/** +* Perform base64 encoding +* @param input some input +* @return base64adecimal representation of input +*/ +template +std::string base64_encode(const std::vector& input) + { + return base64_encode(&input[0], input.size()); + } + +/** +* Perform base64 decoding +* @param output an array of at least input_length*3/4 bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least input_length*3/4 bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least input_length/3*4 bytes +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +secure_vector BOTAN_DLL base64_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +secure_vector BOTAN_DLL base64_decode(const std::string& input, + bool ignore_ws = true); + +} + +#endif diff --git a/src/lib/codec/base64/info.txt b/src/lib/codec/base64/info.txt new file mode 100644 index 000000000..cacae6b0c --- /dev/null +++ b/src/lib/codec/base64/info.txt @@ -0,0 +1 @@ +define BASE64_CODEC 20131128 diff --git a/src/lib/codec/hex/hex.cpp b/src/lib/codec/hex/hex.cpp new file mode 100644 index 000000000..104125894 --- /dev/null +++ b/src/lib/codec/hex/hex.cpp @@ -0,0 +1,204 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +void hex_encode(char output[], + const byte input[], + size_t input_length, + bool uppercase) + { + static const byte BIN_TO_HEX_UPPER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' }; + + static const byte BIN_TO_HEX_LOWER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + + const byte* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER; + + for(size_t i = 0; i != input_length; ++i) + { + byte x = input[i]; + output[2*i ] = tbl[(x >> 4) & 0x0F]; + output[2*i+1] = tbl[(x ) & 0x0F]; + } + } + +std::string hex_encode(const byte input[], + size_t input_length, + bool uppercase) + { + std::string output(2 * input_length, 0); + + if(input_length) + hex_encode(&output[0], input, input_length, uppercase); + + return output; + } + +size_t hex_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws) + { + /* + * Mapping of hex characters to either their binary equivalent + * or to an error code. + * If valid hex (0-9 A-F a-f), the value. + * If whitespace, then 0x80 + * Otherwise 0xFF + * Warning: this table assumes ASCII character encodings + */ + + static const byte HEX_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + byte* out_ptr = output; + bool top_nibble = true; + + clear_mem(output, input_length / 2); + + for(size_t i = 0; i != input_length; ++i) + { + const byte bin = HEX_TO_BIN[static_cast(input[i])]; + + if(bin >= 0x10) + { + if(bin == 0x80 && ignore_ws) + continue; + + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + + throw std::invalid_argument( + std::string("hex_decode: invalid hex character '") + + bad_char + "'"); + } + + *out_ptr |= bin << (top_nibble*4); + + top_nibble = !top_nibble; + if(top_nibble) + ++out_ptr; + } + + input_consumed = input_length; + size_t written = (out_ptr - output); + + /* + * We only got half of a byte at the end; zap the half-written + * output and mark it as unread + */ + if(!top_nibble) + { + *out_ptr = 0; + input_consumed -= 1; + } + + return written; + } + +size_t hex_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = hex_decode(output, input, input_length, + consumed, ignore_ws); + + if(consumed != input_length) + throw std::invalid_argument("hex_decode: input did not have full bytes"); + + return written; + } + +size_t hex_decode(byte output[], + const std::string& input, + bool ignore_ws) + { + return hex_decode(output, &input[0], input.length(), ignore_ws); + } + +secure_vector hex_decode_locked(const char input[], + size_t input_length, + bool ignore_ws) + { + secure_vector bin(1 + input_length / 2); + + size_t written = hex_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +secure_vector hex_decode_locked(const std::string& input, + bool ignore_ws) + { + return hex_decode_locked(&input[0], input.size(), ignore_ws); + } + +std::vector hex_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + std::vector bin(1 + input_length / 2); + + size_t written = hex_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +std::vector hex_decode(const std::string& input, + bool ignore_ws) + { + return hex_decode(&input[0], input.size(), ignore_ws); + } + +} diff --git a/src/lib/codec/hex/hex.h b/src/lib/codec/hex/hex.h new file mode 100644 index 000000000..a64a6c8df --- /dev/null +++ b/src/lib/codec/hex/hex.h @@ -0,0 +1,148 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HEX_CODEC_H__ +#define BOTAN_HEX_CODEC_H__ + +#include +#include + +namespace Botan { + +/** +* Perform hex encoding +* @param output an array of at least input_length*2 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +*/ +void BOTAN_DLL hex_encode(char output[], + const byte input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +std::string BOTAN_DLL hex_encode(const byte input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +template +std::string hex_encode(const std::vector& input, + bool uppercase = true) + { + return hex_encode(&input[0], input.size(), uppercase); + } + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL hex_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL hex_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL hex_decode(byte output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +std::vector BOTAN_DLL +hex_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +std::vector BOTAN_DLL +hex_decode(const std::string& input, + bool ignore_ws = true); + + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +secure_vector BOTAN_DLL +hex_decode_locked(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +secure_vector BOTAN_DLL +hex_decode_locked(const std::string& input, + bool ignore_ws = true); + +} + +#endif diff --git a/src/lib/codec/hex/info.txt b/src/lib/codec/hex/info.txt new file mode 100644 index 000000000..ead5beffd --- /dev/null +++ b/src/lib/codec/hex/info.txt @@ -0,0 +1 @@ +define HEX_CODEC 20131128 diff --git a/src/lib/codec/openpgp/info.txt b/src/lib/codec/openpgp/info.txt new file mode 100644 index 000000000..72467ee72 --- /dev/null +++ b/src/lib/codec/openpgp/info.txt @@ -0,0 +1,8 @@ +define OPENPGP_CODEC 20131128 + +load_on auto + + +crc24 +filters + diff --git a/src/lib/codec/openpgp/openpgp.cpp b/src/lib/codec/openpgp/openpgp.cpp new file mode 100644 index 000000000..7bd811a2f --- /dev/null +++ b/src/lib/codec/openpgp/openpgp.cpp @@ -0,0 +1,196 @@ +/* +* OpenPGP Codec +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* OpenPGP Base64 encoding +*/ +std::string PGP_encode( + const byte input[], size_t length, + const std::string& label, + const std::map& headers) + { + const std::string PGP_HEADER = "-----BEGIN PGP " + label + "-----\n"; + const std::string PGP_TRAILER = "-----END PGP " + label + "-----\n"; + const size_t PGP_WIDTH = 64; + + std::string pgp_encoded = PGP_HEADER; + + if(headers.find("Version") != headers.end()) + pgp_encoded += "Version: " + headers.find("Version")->second + '\n'; + + std::map::const_iterator i = headers.begin(); + while(i != headers.end()) + { + if(i->first != "Version") + pgp_encoded += i->first + ": " + i->second + '\n'; + ++i; + } + pgp_encoded += '\n'; + + Pipe pipe(new Fork( + new Base64_Encoder(true, PGP_WIDTH), + new Chain(new Hash_Filter(new CRC24), new Base64_Encoder) + ) + ); + + pipe.process_msg(input, length); + + pgp_encoded += pipe.read_all_as_string(0); + pgp_encoded += '=' + pipe.read_all_as_string(1) + '\n'; + pgp_encoded += PGP_TRAILER; + + return pgp_encoded; + } + +/* +* OpenPGP Base64 encoding +*/ +std::string PGP_encode(const byte input[], size_t length, + const std::string& type) + { + std::map empty; + return PGP_encode(input, length, type, empty); + } + +/* +* OpenPGP Base64 decoding +*/ +secure_vector PGP_decode(DataSource& source, + std::string& label, + std::map& headers) + { + const size_t RANDOM_CHAR_LIMIT = 5; + + const std::string PGP_HEADER1 = "-----BEGIN PGP "; + const std::string PGP_HEADER2 = "-----"; + size_t position = 0; + + while(position != PGP_HEADER1.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP header found"); + if(b == PGP_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PGP: Malformed PGP header"); + else + position = 0; + } + position = 0; + while(position != PGP_HEADER2.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP header found"); + if(b == PGP_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PGP: Malformed PGP header"); + + if(position == 0) + label += static_cast(b); + } + + headers.clear(); + bool end_of_headers = false; + while(!end_of_headers) + { + std::string this_header; + byte b = 0; + while(b != '\n') + { + if(!source.read_byte(b)) + throw Decoding_Error("PGP: Bad armor header"); + if(b != '\n') + this_header += static_cast(b); + } + + end_of_headers = true; + for(size_t j = 0; j != this_header.length(); ++j) + if(!Charset::is_space(this_header[j])) + end_of_headers = false; + + if(!end_of_headers) + { + std::string::size_type pos = this_header.find(": "); + if(pos == std::string::npos) + throw Decoding_Error("OpenPGP: Bad headers"); + + std::string key = this_header.substr(0, pos); + std::string value = this_header.substr(pos + 2, std::string::npos); + headers[key] = value; + } + } + + Pipe base64(new Base64_Decoder, + new Fork(nullptr, + new Chain(new Hash_Filter(new CRC24), + new Base64_Encoder) + ) + ); + base64.start_msg(); + + const std::string PGP_TRAILER = "-----END PGP " + label + "-----"; + position = 0; + bool newline_seen = 0; + std::string crc; + while(position != PGP_TRAILER.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP trailer found"); + if(b == PGP_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PGP: Malformed PGP trailer"); + + if(b == '=' && newline_seen) + { + while(b != '\n') + { + if(!source.read_byte(b)) + throw Decoding_Error("PGP: Bad CRC tail"); + if(b != '\n') + crc += static_cast(b); + } + } + else if(b == '\n') + newline_seen = true; + else if(position == 0) + { + base64.write(b); + newline_seen = false; + } + } + base64.end_msg(); + + if(crc != "" && crc != base64.read_all_as_string(1)) + throw Decoding_Error("PGP: Corrupt CRC"); + + return base64.read_all(); + } + +/* +* OpenPGP Base64 decoding +*/ +secure_vector PGP_decode(DataSource& source, std::string& label) + { + std::map ignored; + return PGP_decode(source, label, ignored); + } + +} + diff --git a/src/lib/codec/openpgp/openpgp.h b/src/lib/codec/openpgp/openpgp.h new file mode 100644 index 000000000..de56155f2 --- /dev/null +++ b/src/lib/codec/openpgp/openpgp.h @@ -0,0 +1,61 @@ +/* +* OpenPGP Codec +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OPENPGP_CODEC_H__ +#define BOTAN_OPENPGP_CODEC_H__ + +#include +#include +#include + +namespace Botan { + +/** +* @param input the input data +* @param length length of input in bytes +* @param label the human-readable label +* @param headers a set of key/value pairs included in the header +*/ +BOTAN_DLL std::string PGP_encode( + const byte input[], + size_t length, + const std::string& label, + const std::map& headers); + +/** +* @param input the input data +* @param length length of input in bytes +* @param label the human-readable label +*/ +BOTAN_DLL std::string PGP_encode( + const byte input[], + size_t length, + const std::string& label); + +/** +* @param source the input source +* @param label is set to the human-readable label +* @param headers is set to any headers +* @return decoded output as raw binary +*/ +BOTAN_DLL secure_vector PGP_decode( + DataSource& source, + std::string& label, + std::map& headers); + +/** +* @param source the input source +* @param label is set to the human-readable label +* @return decoded output as raw binary +*/ +BOTAN_DLL secure_vector PGP_decode( + DataSource& source, + std::string& label); + +} + +#endif diff --git a/src/lib/codec/pem/info.txt b/src/lib/codec/pem/info.txt new file mode 100644 index 000000000..74b90eef4 --- /dev/null +++ b/src/lib/codec/pem/info.txt @@ -0,0 +1,6 @@ +define PEM_CODEC 20131128 + + +base64 +codec_filt + diff --git a/src/lib/codec/pem/pem.cpp b/src/lib/codec/pem/pem.cpp new file mode 100644 index 000000000..03ec33440 --- /dev/null +++ b/src/lib/codec/pem/pem.cpp @@ -0,0 +1,147 @@ +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace PEM_Code { + +/* +* PEM encode BER/DER-encoded objects +*/ +std::string encode(const byte der[], size_t length, const std::string& label, + size_t width) + { + const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; + const std::string PEM_TRAILER = "-----END " + label + "-----\n"; + + Pipe pipe(new Base64_Encoder(true, width)); + pipe.process_msg(der, length); + return (PEM_HEADER + pipe.read_all_as_string() + PEM_TRAILER); + } + +/* +* Decode PEM down to raw BER/DER +*/ +secure_vector decode_check_label(DataSource& source, + const std::string& label_want) + { + std::string label_got; + secure_vector ber = decode(source, label_got); + if(label_got != label_want) + throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + + ", got " + label_got); + return ber; + } + +/* +* Decode PEM down to raw BER/DER +*/ +secure_vector decode(DataSource& source, std::string& label) + { + const size_t RANDOM_CHAR_LIMIT = 8; + + const std::string PEM_HEADER1 = "-----BEGIN "; + const std::string PEM_HEADER2 = "-----"; + size_t position = 0; + + while(position != PEM_HEADER1.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PEM: Malformed PEM header"); + else + position = 0; + } + position = 0; + while(position != PEM_HEADER2.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM header"); + + if(position == 0) + label += static_cast(b); + } + + Pipe base64(new Base64_Decoder); + base64.start_msg(); + + const std::string PEM_TRAILER = "-----END " + label + "-----"; + position = 0; + while(position != PEM_TRAILER.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM trailer found"); + if(b == PEM_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM trailer"); + + if(position == 0) + base64.write(b); + } + base64.end_msg(); + return base64.read_all(); + } + +secure_vector decode_check_label(const std::string& pem, + const std::string& label_want) + { + DataSource_Memory src(pem); + return decode_check_label(src, label_want); + } + +secure_vector decode(const std::string& pem, std::string& label) + { + DataSource_Memory src(pem); + return decode(src, label); + } + +/* +* Search for a PEM signature +*/ +bool matches(DataSource& source, const std::string& extra, + size_t search_range) + { + const std::string PEM_HEADER = "-----BEGIN " + extra; + + secure_vector search_buf(search_range); + size_t got = source.peek(&search_buf[0], search_buf.size(), 0); + + if(got < PEM_HEADER.length()) + return false; + + size_t index = 0; + + for(size_t j = 0; j != got; ++j) + { + if(search_buf[j] == PEM_HEADER[index]) + ++index; + else + index = 0; + if(index == PEM_HEADER.size()) + return true; + } + return false; + } + +} + +} diff --git a/src/lib/codec/pem/pem.h b/src/lib/codec/pem/pem.h new file mode 100644 index 000000000..a0c6f74aa --- /dev/null +++ b/src/lib/codec/pem/pem.h @@ -0,0 +1,90 @@ +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PEM_H__ +#define BOTAN_PEM_H__ + +#include + +namespace Botan { + +namespace PEM_Code { + +/** +* Encode some binary data in PEM format +*/ +BOTAN_DLL std::string encode(const byte data[], + size_t data_len, + const std::string& label, + size_t line_width = 64); + +/** +* Encode some binary data in PEM format +*/ +inline std::string encode(const std::vector& data, + const std::string& label, + size_t line_width = 64) + { + return encode(&data[0], data.size(), label, line_width); + } + +/** +* Encode some binary data in PEM format +*/ +inline std::string encode(const secure_vector& data, + const std::string& label, + size_t line_width = 64) + { + return encode(&data[0], data.size(), label, line_width); + } + +/** +* Decode PEM data +* @param pem a datasource containing PEM encoded data +* @param label is set to the PEM label found for later inspection +*/ +BOTAN_DLL secure_vector decode(DataSource& pem, + std::string& label); + +/** +* Decode PEM data +* @param pem a string containing PEM encoded data +* @param label is set to the PEM label found for later inspection +*/ +BOTAN_DLL secure_vector decode(const std::string& pem, + std::string& label); + +/** +* Decode PEM data +* @param pem a datasource containing PEM encoded data +* @param label is what we expect the label to be +*/ +BOTAN_DLL secure_vector decode_check_label( + DataSource& pem, + const std::string& label); + +/** +* Decode PEM data +* @param pem a string containing PEM encoded data +* @param label is what we expect the label to be +*/ +BOTAN_DLL secure_vector decode_check_label( + const std::string& pem, + const std::string& label); + +/** +* Heuristic test for PEM data. +*/ +BOTAN_DLL bool matches(DataSource& source, + const std::string& extra = "", + size_t search_range = 4096); + +} + +} + +#endif diff --git a/src/lib/constructs/aont/info.txt b/src/lib/constructs/aont/info.txt new file mode 100644 index 000000000..fb66d4129 --- /dev/null +++ b/src/lib/constructs/aont/info.txt @@ -0,0 +1,8 @@ +define PACKAGE_TRANSFORM 20131128 + + +block +ctr +rng +filters + diff --git a/src/lib/constructs/aont/package.cpp b/src/lib/constructs/aont/package.cpp new file mode 100644 index 000000000..1adee90e8 --- /dev/null +++ b/src/lib/constructs/aont/package.cpp @@ -0,0 +1,120 @@ +/* +* Rivest's Package Tranform +* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +void aont_package(RandomNumberGenerator& rng, + BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]) + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(!cipher->valid_keylength(BLOCK_SIZE)) + throw Invalid_Argument("AONT::package: Invalid cipher"); + + // The all-zero string which is used both as the CTR IV and as K0 + const std::string all_zeros(BLOCK_SIZE*2, '0'); + + SymmetricKey package_key(rng, BLOCK_SIZE); + + Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); + + pipe.process_msg(input, input_len); + pipe.read(output, pipe.remaining()); + + // Set K0 (the all zero key) + cipher->set_key(SymmetricKey(all_zeros)); + + secure_vector buf(BLOCK_SIZE); + + const size_t blocks = + (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE; + + byte* final_block = output + input_len; + clear_mem(final_block, BLOCK_SIZE); + + // XOR the hash blocks into the final block + for(size_t i = 0; i != blocks; ++i) + { + const size_t left = std::min(BLOCK_SIZE, + input_len - BLOCK_SIZE * i); + + zeroise(buf); + copy_mem(&buf[0], output + (BLOCK_SIZE * i), left); + + for(size_t j = 0; j != sizeof(i); ++j) + buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); + + cipher->encrypt(&buf[0]); + + xor_buf(&final_block[0], &buf[0], BLOCK_SIZE); + } + + // XOR the random package key into the final block + xor_buf(&final_block[0], package_key.begin(), BLOCK_SIZE); + } + +void aont_unpackage(BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]) + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(!cipher->valid_keylength(BLOCK_SIZE)) + throw Invalid_Argument("AONT::unpackage: Invalid cipher"); + + if(input_len < BLOCK_SIZE) + throw Invalid_Argument("AONT::unpackage: Input too short"); + + // The all-zero string which is used both as the CTR IV and as K0 + const std::string all_zeros(BLOCK_SIZE*2, '0'); + + cipher->set_key(SymmetricKey(all_zeros)); + + secure_vector package_key(BLOCK_SIZE); + secure_vector buf(BLOCK_SIZE); + + // Copy the package key (masked with the block hashes) + copy_mem(&package_key[0], + input + (input_len - BLOCK_SIZE), + BLOCK_SIZE); + + const size_t blocks = ((input_len - 1) / BLOCK_SIZE); + + // XOR the blocks into the package key bits + for(size_t i = 0; i != blocks; ++i) + { + const size_t left = std::min(BLOCK_SIZE, + input_len - BLOCK_SIZE * (i+1)); + + zeroise(buf); + copy_mem(&buf[0], input + (BLOCK_SIZE * i), left); + + for(size_t j = 0; j != sizeof(i); ++j) + buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); + + cipher->encrypt(&buf[0]); + + xor_buf(&package_key[0], &buf[0], BLOCK_SIZE); + } + + Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); + + pipe.process_msg(input, input_len - BLOCK_SIZE); + + pipe.read(output, pipe.remaining()); + } + +} diff --git a/src/lib/constructs/aont/package.h b/src/lib/constructs/aont/package.h new file mode 100644 index 000000000..52d1c2190 --- /dev/null +++ b/src/lib/constructs/aont/package.h @@ -0,0 +1,44 @@ +/* +* Rivest's Package Tranform +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AONT_PACKAGE_TRANSFORM_H__ +#define BOTAN_AONT_PACKAGE_TRANSFORM_H__ + +#include +#include + +namespace Botan { + +/** +* Rivest's Package Tranform +* @param rng the random number generator to use +* @param cipher the block cipher to use +* @param input the input data buffer +* @param input_len the length of the input data in bytes +* @param output the output data buffer (must be at least +* input_len + cipher->BLOCK_SIZE bytes long) +*/ +void BOTAN_DLL aont_package(RandomNumberGenerator& rng, + BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]); + +/** +* Rivest's Package Tranform (Inversion) +* @param cipher the block cipher to use +* @param input the input data buffer +* @param input_len the length of the input data in bytes +* @param output the output data buffer (must be at least +* input_len - cipher->BLOCK_SIZE bytes long) +*/ +void BOTAN_DLL aont_unpackage(BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]); + +} + +#endif diff --git a/src/lib/constructs/cryptobox/cryptobox.cpp b/src/lib/constructs/cryptobox/cryptobox.cpp new file mode 100644 index 000000000..aa2369c6c --- /dev/null +++ b/src/lib/constructs/cryptobox/cryptobox.cpp @@ -0,0 +1,163 @@ +/* +* Cryptobox Message Routines +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace CryptoBox { + +namespace { + +/* +First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits +for later use as flags, etc if needed +*/ +const u32bit CRYPTOBOX_VERSION_CODE = 0xEFC22400; + +const size_t VERSION_CODE_LEN = 4; +const size_t CIPHER_KEY_LEN = 32; +const size_t CIPHER_IV_LEN = 16; +const size_t MAC_KEY_LEN = 32; +const size_t MAC_OUTPUT_LEN = 20; +const size_t PBKDF_SALT_LEN = 10; +const size_t PBKDF_ITERATIONS = 8 * 1024; + +const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + CIPHER_IV_LEN + MAC_KEY_LEN; + +} + +std::string encrypt(const byte input[], size_t input_len, + const std::string& passphrase, + RandomNumberGenerator& rng) + { + secure_vector pbkdf_salt(PBKDF_SALT_LEN); + rng.randomize(&pbkdf_salt[0], pbkdf_salt.size()); + + PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512)); + + OctetString master_key = pbkdf.derive_key( + PBKDF_OUTPUT_LEN, + passphrase, + &pbkdf_salt[0], + pbkdf_salt.size(), + PBKDF_ITERATIONS); + + const byte* mk = master_key.begin(); + + SymmetricKey cipher_key(&mk[0], CIPHER_KEY_LEN); + SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN); + InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN); + + Pipe pipe(get_cipher("Serpent/CTR-BE", cipher_key, iv, ENCRYPTION), + new Fork( + nullptr, + new MAC_Filter(new HMAC(new SHA_512), + mac_key, MAC_OUTPUT_LEN))); + + pipe.process_msg(input, input_len); + + /* + Output format is: + version # (4 bytes) + salt (10 bytes) + mac (20 bytes) + ciphertext + */ + const size_t ciphertext_len = pipe.remaining(0); + + std::vector out_buf(VERSION_CODE_LEN + + PBKDF_SALT_LEN + + MAC_OUTPUT_LEN + + ciphertext_len); + + for(size_t i = 0; i != VERSION_CODE_LEN; ++i) + out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE); + + copy_mem(&out_buf[VERSION_CODE_LEN], &pbkdf_salt[0], PBKDF_SALT_LEN); + + pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], MAC_OUTPUT_LEN, 1); + pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN], + ciphertext_len, 0); + + return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE"); + } + +std::string decrypt(const byte input[], size_t input_len, + const std::string& passphrase) + { + DataSource_Memory input_src(input, input_len); + secure_vector ciphertext = + PEM_Code::decode_check_label(input_src, + "BOTAN CRYPTOBOX MESSAGE"); + + if(ciphertext.size() < (VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN)) + throw Decoding_Error("Invalid CryptoBox input"); + + for(size_t i = 0; i != VERSION_CODE_LEN; ++i) + if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE)) + throw Decoding_Error("Bad CryptoBox version"); + + const byte* pbkdf_salt = &ciphertext[VERSION_CODE_LEN]; + + PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512)); + + OctetString master_key = pbkdf.derive_key( + PBKDF_OUTPUT_LEN, + passphrase, + pbkdf_salt, + PBKDF_SALT_LEN, + PBKDF_ITERATIONS); + + const byte* mk = master_key.begin(); + + SymmetricKey cipher_key(&mk[0], CIPHER_KEY_LEN); + SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN); + InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN); + + Pipe pipe(new Fork( + get_cipher("Serpent/CTR-BE", cipher_key, iv, DECRYPTION), + new MAC_Filter(new HMAC(new SHA_512), + mac_key, MAC_OUTPUT_LEN))); + + const size_t ciphertext_offset = + VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN; + + pipe.process_msg(&ciphertext[ciphertext_offset], + ciphertext.size() - ciphertext_offset); + + byte computed_mac[MAC_OUTPUT_LEN]; + pipe.read(computed_mac, MAC_OUTPUT_LEN, 1); + + if(!same_mem(computed_mac, + &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN], + MAC_OUTPUT_LEN)) + throw Decoding_Error("CryptoBox integrity failure"); + + return pipe.read_all_as_string(0); + } + +std::string decrypt(const std::string& input, + const std::string& passphrase) + { + return decrypt(reinterpret_cast(&input[0]), + input.size(), + passphrase); + } + +} + +} diff --git a/src/lib/constructs/cryptobox/cryptobox.h b/src/lib/constructs/cryptobox/cryptobox.h new file mode 100644 index 000000000..7a363f72d --- /dev/null +++ b/src/lib/constructs/cryptobox/cryptobox.h @@ -0,0 +1,55 @@ +/* +* Cryptobox Message Routines +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CRYPTOBOX_H__ +#define BOTAN_CRYPTOBOX_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This namespace holds various high-level crypto functions +*/ +namespace CryptoBox { + +/** +* Encrypt a message using a passphrase +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +* @param rng a ref to a random number generator, such as AutoSeeded_RNG +*/ +BOTAN_DLL std::string encrypt(const byte input[], size_t input_len, + const std::string& passphrase, + RandomNumberGenerator& rng); + + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_DLL std::string decrypt(const byte input[], size_t input_len, + const std::string& passphrase); + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_DLL std::string decrypt(const std::string& input, + const std::string& passphrase); + +} + +} + +#endif diff --git a/src/lib/constructs/cryptobox/info.txt b/src/lib/constructs/cryptobox/info.txt new file mode 100644 index 000000000..b7bf6e4e8 --- /dev/null +++ b/src/lib/constructs/cryptobox/info.txt @@ -0,0 +1,13 @@ +define CRYPTO_BOX 20131128 + + +filters +ctr +hmac +rng +serpent +sha2_64 +base64 +pbkdf2 +pem + diff --git a/src/lib/constructs/cryptobox_psk/cryptobox_psk.cpp b/src/lib/constructs/cryptobox_psk/cryptobox_psk.cpp new file mode 100644 index 000000000..f22e43b43 --- /dev/null +++ b/src/lib/constructs/cryptobox_psk/cryptobox_psk.cpp @@ -0,0 +1,134 @@ +/* +* Cryptobox Message Routines +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace CryptoBox { + +namespace { + +const u32bit CRYPTOBOX_MAGIC = 0x571B0E4F; +const std::string CRYPTOBOX_CIPHER = "AES-256/CBC"; +const std::string CRYPTOBOX_MAC = "HMAC(SHA-256)"; +const std::string CRYPTOBOX_KDF = "KDF2(SHA-256)"; + +const size_t MAGIC_LENGTH = 4; +const size_t KEY_KDF_SALT_LENGTH = 10; +const size_t MAC_KEY_LENGTH = 32; +const size_t CIPHER_KEY_LENGTH = 32; +const size_t CIPHER_IV_LENGTH = 16; +const size_t MAC_OUTPUT_LENGTH = 32; + +} + +std::vector encrypt(const byte input[], size_t input_len, + const SymmetricKey& master_key, + RandomNumberGenerator& rng) + { + std::unique_ptr kdf(get_kdf(CRYPTOBOX_KDF)); + + const secure_vector cipher_key_salt = + rng.random_vec(KEY_KDF_SALT_LENGTH); + + const secure_vector mac_key_salt = + rng.random_vec(KEY_KDF_SALT_LENGTH); + + SymmetricKey cipher_key = + kdf->derive_key(CIPHER_KEY_LENGTH, + master_key.bits_of(), + cipher_key_salt); + + SymmetricKey mac_key = + kdf->derive_key(MAC_KEY_LENGTH, + master_key.bits_of(), + mac_key_salt); + + InitializationVector cipher_iv(rng, 16); + + std::unique_ptr mac(get_mac(CRYPTOBOX_MAC)); + mac->set_key(mac_key); + + Pipe pipe(get_cipher(CRYPTOBOX_CIPHER, cipher_key, cipher_iv, ENCRYPTION)); + pipe.process_msg(input, input_len); + secure_vector ctext = pipe.read_all(0); + + std::vector out(MAGIC_LENGTH); + store_be(CRYPTOBOX_MAGIC, &out[0]); + out += cipher_key_salt; + out += mac_key_salt; + out += cipher_iv.bits_of(); + out += ctext; + + mac->update(out); + + out += mac->final(); + return out; + } + +secure_vector decrypt(const byte input[], size_t input_len, + const SymmetricKey& master_key) + { + const size_t MIN_CTEXT_SIZE = 16; // due to using CBC with padding + + const size_t MIN_POSSIBLE_LENGTH = + MAGIC_LENGTH + + 2 * KEY_KDF_SALT_LENGTH + + CIPHER_IV_LENGTH + + MIN_CTEXT_SIZE + + MAC_OUTPUT_LENGTH; + + if(input_len < MIN_POSSIBLE_LENGTH) + throw Decoding_Error("Encrypted input too short to be valid"); + + if(load_be(input, 0) != CRYPTOBOX_MAGIC) + throw Decoding_Error("Unknown header value in cryptobox"); + + std::unique_ptr kdf(get_kdf(CRYPTOBOX_KDF)); + + const byte* cipher_key_salt = &input[MAGIC_LENGTH]; + + const byte* mac_key_salt = &input[MAGIC_LENGTH + KEY_KDF_SALT_LENGTH]; + + SymmetricKey mac_key = kdf->derive_key(MAC_KEY_LENGTH, + master_key.bits_of(), + mac_key_salt, + KEY_KDF_SALT_LENGTH); + + std::unique_ptr mac(get_mac(CRYPTOBOX_MAC)); + mac->set_key(mac_key); + + mac->update(&input[0], input_len - MAC_OUTPUT_LENGTH); + secure_vector computed_mac = mac->final(); + + if(!same_mem(&input[input_len - MAC_OUTPUT_LENGTH], &computed_mac[0], computed_mac.size())) + throw Decoding_Error("MAC verification failed"); + + SymmetricKey cipher_key = + kdf->derive_key(CIPHER_KEY_LENGTH, + master_key.bits_of(), + cipher_key_salt, KEY_KDF_SALT_LENGTH); + + InitializationVector cipher_iv(&input[MAGIC_LENGTH+2*KEY_KDF_SALT_LENGTH], + CIPHER_IV_LENGTH); + + const size_t CTEXT_OFFSET = MAGIC_LENGTH + 2 * KEY_KDF_SALT_LENGTH + CIPHER_IV_LENGTH; + + Pipe pipe(get_cipher(CRYPTOBOX_CIPHER, cipher_key, cipher_iv, DECRYPTION)); + pipe.process_msg(&input[CTEXT_OFFSET], + input_len - (MAC_OUTPUT_LENGTH + CTEXT_OFFSET)); + return pipe.read_all(); + } + +} + +} diff --git a/src/lib/constructs/cryptobox_psk/cryptobox_psk.h b/src/lib/constructs/cryptobox_psk/cryptobox_psk.h new file mode 100644 index 000000000..2f16ee461 --- /dev/null +++ b/src/lib/constructs/cryptobox_psk/cryptobox_psk.h @@ -0,0 +1,47 @@ +/* +* Cryptobox Message Routines +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CRYPTOBOX_PSK_H__ +#define BOTAN_CRYPTOBOX_PSK_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This namespace holds various high-level crypto functions +*/ +namespace CryptoBox { + +/** +* Encrypt a message using a shared secret key +* @param input the input data +* @param input_len the length of input in bytes +* @param key the key used to encrypt the message +* @param rng a ref to a random number generator, such as AutoSeeded_RNG +*/ +BOTAN_DLL std::vector encrypt(const byte input[], size_t input_len, + const SymmetricKey& key, + RandomNumberGenerator& rng); + +/** +* Encrypt a message using a shared secret key +* @param input the input data +* @param input_len the length of input in bytes +* @param key the key used to encrypt the message +* @param rng a ref to a random number generator, such as AutoSeeded_RNG +*/ +BOTAN_DLL secure_vector decrypt(const byte input[], size_t input_len, + const SymmetricKey& key); + +} + +} + +#endif diff --git a/src/lib/constructs/cryptobox_psk/info.txt b/src/lib/constructs/cryptobox_psk/info.txt new file mode 100644 index 000000000..03f7525f5 --- /dev/null +++ b/src/lib/constructs/cryptobox_psk/info.txt @@ -0,0 +1,10 @@ +define CRYPTOBOX_PSK 20131128 + + +aes +cbc +hmac +kdf2 +rng +sha2_64 + diff --git a/src/lib/constructs/fpe_fe1/fpe_fe1.cpp b/src/lib/constructs/fpe_fe1/fpe_fe1.cpp new file mode 100644 index 000000000..b22d3a8df --- /dev/null +++ b/src/lib/constructs/fpe_fe1/fpe_fe1.cpp @@ -0,0 +1,193 @@ +/* +* Format Preserving Encryption using the scheme FE1 from the paper +* "Format-Preserving Encryption" by Bellare, Rogaway, et al +* (http://eprint.iacr.org/2009/251) +* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace FPE { + +namespace { + +// Normally FPE is for SSNs, CC#s, etc, nothing too big +const size_t MAX_N_BYTES = 128/8; + +/* +* Factor n into a and b which are as close together as possible. +* Assumes n is composed mostly of small factors which is the case for +* typical uses of FPE (typically, n is a power of 10) +* +* Want a >= b since the safe number of rounds is 2+log_a(b); if a >= b +* then this is always 3 +*/ +void factor(BigInt n, BigInt& a, BigInt& b) + { + a = 1; + b = 1; + + size_t n_low_zero = low_zero_bits(n); + + a <<= (n_low_zero / 2); + b <<= n_low_zero - (n_low_zero / 2); + n >>= n_low_zero; + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + while(n % PRIMES[i] == 0) + { + a *= PRIMES[i]; + if(a > b) + std::swap(a, b); + n /= PRIMES[i]; + } + } + + if(a > b) + std::swap(a, b); + a *= n; + if(a < b) + std::swap(a, b); + + if(a <= 1 || b <= 1) + throw std::runtime_error("Could not factor n for use in FPE"); + } + +/* +* According to a paper by Rogaway, Bellare, etc, the min safe number +* of rounds to use for FPE is 2+log_a(b). If a >= b then log_a(b) <= 1 +* so 3 rounds is safe. The FPE factorization routine should always +* return a >= b, so just confirm that and return 3. +*/ +size_t rounds(const BigInt& a, const BigInt& b) + { + if(a < b) + throw std::logic_error("FPE rounds: a < b"); + return 3; + } + +/* +* A simple round function based on HMAC(SHA-256) +*/ +class FPE_Encryptor + { + public: + FPE_Encryptor(const SymmetricKey& key, + const BigInt& n, + const std::vector& tweak); + + ~FPE_Encryptor() { delete mac; } + + BigInt operator()(size_t i, const BigInt& R); + + private: + MessageAuthenticationCode* mac; + std::vector mac_n_t; + }; + +FPE_Encryptor::FPE_Encryptor(const SymmetricKey& key, + const BigInt& n, + const std::vector& tweak) + { + mac = new HMAC(new SHA_256); + mac->set_key(key); + + std::vector n_bin = BigInt::encode(n); + + if(n_bin.size() > MAX_N_BYTES) + throw std::runtime_error("N is too large for FPE encryption"); + + mac->update_be(static_cast(n_bin.size())); + mac->update(&n_bin[0], n_bin.size()); + + mac->update_be(static_cast(tweak.size())); + mac->update(&tweak[0], tweak.size()); + + mac_n_t = unlock(mac->final()); + } + +BigInt FPE_Encryptor::operator()(size_t round_no, const BigInt& R) + { + secure_vector r_bin = BigInt::encode_locked(R); + + mac->update(mac_n_t); + mac->update_be(static_cast(round_no)); + + mac->update_be(static_cast(r_bin.size())); + mac->update(&r_bin[0], r_bin.size()); + + secure_vector X = mac->final(); + return BigInt(&X[0], X.size()); + } + +} + +/* +* Generic Z_n FPE encryption, FE1 scheme +*/ +BigInt fe1_encrypt(const BigInt& n, const BigInt& X0, + const SymmetricKey& key, + const std::vector& tweak) + { + FPE_Encryptor F(key, n, tweak); + + BigInt a, b; + factor(n, a, b); + + const size_t r = rounds(a, b); + + BigInt X = X0; + + for(size_t i = 0; i != r; ++i) + { + BigInt L = X / b; + BigInt R = X % b; + + BigInt W = (L + F(i, R)) % a; + X = a * R + W; + } + + return X; + } + +/* +* Generic Z_n FPE decryption, FD1 scheme +*/ +BigInt fe1_decrypt(const BigInt& n, const BigInt& X0, + const SymmetricKey& key, + const std::vector& tweak) + { + FPE_Encryptor F(key, n, tweak); + + BigInt a, b; + factor(n, a, b); + + const size_t r = rounds(a, b); + + BigInt X = X0; + + for(size_t i = 0; i != r; ++i) + { + BigInt W = X % a; + BigInt R = X / a; + + BigInt L = (W - F(r-i-1, R)) % a; + X = b * L + R; + } + + return X; + } + +} + +} diff --git a/src/lib/constructs/fpe_fe1/fpe_fe1.h b/src/lib/constructs/fpe_fe1/fpe_fe1.h new file mode 100644 index 000000000..66e7f1cfa --- /dev/null +++ b/src/lib/constructs/fpe_fe1/fpe_fe1.h @@ -0,0 +1,44 @@ +/* +* Format Preserving Encryption (FE1 scheme) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_FPE_FE1_H__ +#define BOTAN_FPE_FE1_H__ + +#include +#include + +namespace Botan { + +namespace FPE { + +/** +* Encrypt X from and onto the group Z_n using key and tweak +* @param n the modulus +* @param X the plaintext as a BigInt +* @param key a random key +* @param tweak will modify the ciphertext (think of as an IV) +*/ +BigInt BOTAN_DLL fe1_encrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const std::vector& tweak); + +/** +* Decrypt X from and onto the group Z_n using key and tweak +* @param n the modulus +* @param X the ciphertext as a BigInt +* @param key is the key used for encryption +* @param tweak the same tweak used for encryption +*/ +BigInt BOTAN_DLL fe1_decrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const std::vector& tweak); + +} + +} + +#endif diff --git a/src/lib/constructs/fpe_fe1/info.txt b/src/lib/constructs/fpe_fe1/info.txt new file mode 100644 index 000000000..42264e54e --- /dev/null +++ b/src/lib/constructs/fpe_fe1/info.txt @@ -0,0 +1,7 @@ +define FPE_FE1 20131128 + + +hmac +sha2_32 +bigint + diff --git a/src/lib/constructs/rfc3394/info.txt b/src/lib/constructs/rfc3394/info.txt new file mode 100644 index 000000000..4b62b16e3 --- /dev/null +++ b/src/lib/constructs/rfc3394/info.txt @@ -0,0 +1 @@ +define RFC3394_KEYWRAP 20131128 diff --git a/src/lib/constructs/rfc3394/rfc3394.cpp b/src/lib/constructs/rfc3394/rfc3394.cpp new file mode 100644 index 000000000..cfe95f40b --- /dev/null +++ b/src/lib/constructs/rfc3394/rfc3394.cpp @@ -0,0 +1,122 @@ +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +BlockCipher* make_aes(size_t keylength, + Algorithm_Factory& af) + { + if(keylength == 16) + return af.make_block_cipher("AES-128"); + else if(keylength == 24) + return af.make_block_cipher("AES-192"); + else if(keylength == 32) + return af.make_block_cipher("AES-256"); + else + throw std::invalid_argument("Bad KEK length for NIST keywrap"); + } + +} + +secure_vector rfc3394_keywrap(const secure_vector& key, + const SymmetricKey& kek, + Algorithm_Factory& af) + { + if(key.size() % 8 != 0) + throw std::invalid_argument("Bad input key size for NIST key wrap"); + + std::unique_ptr aes(make_aes(kek.length(), af)); + aes->set_key(kek); + + const size_t n = key.size() / 8; + + secure_vector R((n + 1) * 8); + secure_vector A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = 0xA6; + + copy_mem(&R[8], &key[0], key.size()); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = 1; i <= n; ++i) + { + const u32bit t = (n * j) + i; + + copy_mem(&A[8], &R[8*i], 8); + + aes->encrypt(&A[0]); + copy_mem(&R[8*i], &A[8], 8); + + byte t_buf[4] = { 0 }; + store_be(t, t_buf); + xor_buf(&A[4], &t_buf[0], 4); + } + } + + copy_mem(&R[0], &A[0], 8); + + return R; + } + +secure_vector rfc3394_keyunwrap(const secure_vector& key, + const SymmetricKey& kek, + Algorithm_Factory& af) + { + if(key.size() < 16 || key.size() % 8 != 0) + throw std::invalid_argument("Bad input key size for NIST key unwrap"); + + std::unique_ptr aes(make_aes(kek.length(), af)); + aes->set_key(kek); + + const size_t n = (key.size() - 8) / 8; + + secure_vector R(n * 8); + secure_vector A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = key[i]; + + copy_mem(&R[0], &key[8], key.size() - 8); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = n; i != 0; --i) + { + const u32bit t = (5 - j) * n + i; + + byte t_buf[4] = { 0 }; + store_be(t, t_buf); + + xor_buf(&A[4], &t_buf[0], 4); + + copy_mem(&A[8], &R[8*(i-1)], 8); + + aes->decrypt(&A[0]); + + copy_mem(&R[8*(i-1)], &A[8], 8); + } + } + + if(load_be(&A[0], 0) != 0xA6A6A6A6A6A6A6A6) + throw Integrity_Failure("NIST key unwrap failed"); + + return R; + } + +} diff --git a/src/lib/constructs/rfc3394/rfc3394.h b/src/lib/constructs/rfc3394/rfc3394.h new file mode 100644 index 000000000..febd5207e --- /dev/null +++ b/src/lib/constructs/rfc3394/rfc3394.h @@ -0,0 +1,45 @@ +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_KEY_WRAP_H__ +#define BOTAN_AES_KEY_WRAP_H__ + +#include + +namespace Botan { + +class Algorithm_Factory; + +/** +* Encrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the plaintext key to encrypt +* @param kek the key encryption key +* @param af an algorithm factory +* @return key encrypted under kek +*/ +secure_vector BOTAN_DLL rfc3394_keywrap(const secure_vector& key, + const SymmetricKey& kek, + Algorithm_Factory& af); + +/** +* Decrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the encrypted key to decrypt +* @param kek the key encryption key +* @param af an algorithm factory +* @return key decrypted under kek +*/ +secure_vector BOTAN_DLL rfc3394_keyunwrap(const secure_vector& key, + const SymmetricKey& kek, + Algorithm_Factory& af); + +} + +#endif diff --git a/src/lib/constructs/srp6/info.txt b/src/lib/constructs/srp6/info.txt new file mode 100644 index 000000000..1d1c4ba96 --- /dev/null +++ b/src/lib/constructs/srp6/info.txt @@ -0,0 +1,7 @@ +define SRP6 20131128 + + +bigint +hash +dl_group + diff --git a/src/lib/constructs/srp6/srp6.cpp b/src/lib/constructs/srp6/srp6.cpp new file mode 100644 index 000000000..7bc879350 --- /dev/null +++ b/src/lib/constructs/srp6/srp6.cpp @@ -0,0 +1,163 @@ +/* +* SRP-6a (RFC 5054 compatatible) +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +BigInt hash_seq(const std::string& hash_id, + size_t pad_to, + const BigInt& in1, + const BigInt& in2) + { + std::unique_ptr hash_fn( + global_state().algorithm_factory().make_hash_function(hash_id)); + + hash_fn->update(BigInt::encode_1363(in1, pad_to)); + hash_fn->update(BigInt::encode_1363(in2, pad_to)); + + return BigInt::decode(hash_fn->final()); + } + +BigInt compute_x(const std::string& hash_id, + const std::string& identifier, + const std::string& password, + const std::vector& salt) + { + std::unique_ptr hash_fn( + global_state().algorithm_factory().make_hash_function(hash_id)); + + hash_fn->update(identifier); + hash_fn->update(":"); + hash_fn->update(password); + + secure_vector inner_h = hash_fn->final(); + + hash_fn->update(salt); + hash_fn->update(inner_h); + + secure_vector outer_h = hash_fn->final(); + + return BigInt::decode(outer_h); + } + +} + +std::string srp6_group_identifier(const BigInt& N, const BigInt& g) + { + /* + This function assumes that only one 'standard' SRP parameter set has + been defined for a particular bitsize. As of this writing that is the case. + */ + try + { + const std::string group_name = "modp/srp/" + std::to_string(N.bits()); + + DL_Group group(group_name); + + if(group.get_p() == N && group.get_g() == g) + return group_name; + + throw std::runtime_error("Unknown SRP params"); + } + catch(...) + { + throw Invalid_Argument("Bad SRP group parameters"); + } + } + +std::pair +srp6_client_agree(const std::string& identifier, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const std::vector& salt, + const BigInt& B, + RandomNumberGenerator& rng) + { + DL_Group group(group_id); + const BigInt& g = group.get_g(); + const BigInt& p = group.get_p(); + + const size_t p_bytes = group.get_p().bytes(); + + if(B <= 0 || B >= p) + throw std::runtime_error("Invalid SRP parameter from server"); + + BigInt k = hash_seq(hash_id, p_bytes, p, g); + + BigInt a(rng, 256); + + BigInt A = power_mod(g, a, p); + + BigInt u = hash_seq(hash_id, p_bytes, A, B); + + const BigInt x = compute_x(hash_id, identifier, password, salt); + + BigInt S = power_mod((B - (k * power_mod(g, x, p))) % p, (a + (u * x)), p); + + SymmetricKey Sk(BigInt::encode_1363(S, p_bytes)); + + return std::make_pair(A, Sk); + } + +BigInt generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const std::vector& salt, + const std::string& group_id, + const std::string& hash_id) + { + const BigInt x = compute_x(hash_id, identifier, password, salt); + + DL_Group group(group_id); + return power_mod(group.get_g(), x, group.get_p()); + } + +BigInt SRP6_Server_Session::step1(const BigInt& v, + const std::string& group_id, + const std::string& hash_id, + RandomNumberGenerator& rng) + { + DL_Group group(group_id); + const BigInt& g = group.get_g(); + const BigInt& p = group.get_p(); + + p_bytes = p.bytes(); + + BigInt k = hash_seq(hash_id, p_bytes, p, g); + + BigInt b(rng, 256); + + B = (v*k + power_mod(g, b, p)) % p; + + this->v = v; + this->b = b; + this->p = p; + this->hash_id = hash_id; + + return B; + } + +SymmetricKey SRP6_Server_Session::step2(const BigInt& A) + { + if(A <= 0 || A >= p) + throw std::runtime_error("Invalid SRP parameter from client"); + + BigInt u = hash_seq(hash_id, p_bytes, A, B); + + BigInt S = power_mod(A * power_mod(v, u, p), b, p); + + return BigInt::encode_1363(S, p_bytes); + } + +} diff --git a/src/lib/constructs/srp6/srp6.h b/src/lib/constructs/srp6/srp6.h new file mode 100644 index 000000000..6f3960be1 --- /dev/null +++ b/src/lib/constructs/srp6/srp6.h @@ -0,0 +1,97 @@ +/* +* SRP-6a (RFC 5054 compatatible) +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RFC5054_SRP6_H__ +#define BOTAN_RFC5054_SRP6_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* SRP6a Client side +* @param username the username we are attempting login for +* @param password the password we are attempting to use +* @param group_id specifies the shared SRP group +* @param hash_id specifies a secure hash function +* @param salt is the salt value sent by the server +* @param B is the server's public value +* @param rng is a random number generator +* +* @return (A,K) the client public key and the shared secret key +*/ +std::pair +BOTAN_DLL srp6_client_agree(const std::string& username, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const std::vector& salt, + const BigInt& B, + RandomNumberGenerator& rng); + +/** +* Generate a new SRP-6 verifier +* @param identifier a username or other client identifier +* @param password the secret used to authenticate user +* @param salt a randomly chosen value, at least 128 bits long +* @param group_id specifies the shared SRP group +* @param hash_id specifies a secure hash function +*/ +BigInt BOTAN_DLL generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const std::vector& salt, + const std::string& group_id, + const std::string& hash_id); + +/** +* Return the group id for this SRP param set, or else thrown an +* exception +* @param N the group modulus +* @param g the group generator +* @return group identifier +*/ +std::string BOTAN_DLL srp6_group_identifier(const BigInt& N, const BigInt& g); + +/** +* Represents a SRP-6a server session +*/ +class BOTAN_DLL SRP6_Server_Session + { + public: + /** + * Server side step 1 + * @param v the verification value saved from client registration + * @param group_id the SRP group id + * @param hash_id the SRP hash in use + * @param rng a random number generator + * @return SRP-6 B value + */ + BigInt step1(const BigInt& v, + const std::string& group_id, + const std::string& hash_id, + RandomNumberGenerator& rng); + + /** + * Server side step 2 + * @param A the client's value + * @return shared symmetric key + */ + SymmetricKey step2(const BigInt& A); + + private: + std::string hash_id; + BigInt B, b, v, S, p; + size_t p_bytes; + }; + +} + +#endif diff --git a/src/lib/constructs/srp6/srp6_files.cpp b/src/lib/constructs/srp6/srp6_files.cpp new file mode 100644 index 000000000..4df2986f3 --- /dev/null +++ b/src/lib/constructs/srp6/srp6_files.cpp @@ -0,0 +1,69 @@ +/* +* SRP-6a File Handling +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +SRP6_Authenticator_File::SRP6_Authenticator_File(const std::string& filename) + { + std::ifstream in(filename.c_str()); + + if(!in) + return; // no entries + + while(in.good()) + { + std::string line; + std::getline(in, line); + + std::vector parts = split_on(line, ':'); + + if(parts.size() != 4) + throw Decoding_Error("Invalid line in SRP authenticator file"); + + std::string username = parts[0]; + BigInt v = BigInt::decode(base64_decode(parts[1])); + std::vector salt = unlock(base64_decode(parts[2])); + BigInt group_id_idx = BigInt::decode(base64_decode(parts[3])); + + std::string group_id; + + if(group_id_idx == 1) + group_id = "modp/srp/1024"; + else if(group_id_idx == 2) + group_id = "modp/srp/1536"; + else if(group_id_idx == 3) + group_id = "modp/srp/2048"; + else + continue; // unknown group, ignored + + entries[username] = SRP6_Data(v, salt, group_id); + } + } + +bool SRP6_Authenticator_File::lookup_user(const std::string& username, + BigInt& v, + std::vector& salt, + std::string& group_id) const + { + std::map::const_iterator i = entries.find(username); + + if(i == entries.end()) + return false; + + v = i->second.v; + salt = i->second.salt; + group_id = i->second.group_id; + + return true; + } + +} diff --git a/src/lib/constructs/srp6/srp6_files.h b/src/lib/constructs/srp6/srp6_files.h new file mode 100644 index 000000000..4e0d3ff02 --- /dev/null +++ b/src/lib/constructs/srp6/srp6_files.h @@ -0,0 +1,53 @@ +/* +* SRP-6a File Handling +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SRP6A_FILES_H__ +#define BOTAN_SRP6A_FILES_H__ + +#include +#include +#include + +namespace Botan { + +/** +* A GnuTLS compatible SRP6 authenticator file +*/ +class BOTAN_DLL SRP6_Authenticator_File + { + public: + /** + * @param filename will be opened and processed as a SRP + * authenticator file + */ + SRP6_Authenticator_File(const std::string& filename); + + bool lookup_user(const std::string& username, + BigInt& v, + std::vector& salt, + std::string& group_id) const; + private: + struct SRP6_Data + { + SRP6_Data() {} + + SRP6_Data(const BigInt& v, + const std::vector& salt, + const std::string& group_id) : + v(v), salt(salt), group_id(group_id) {} + + BigInt v; + std::vector salt; + std::string group_id; + }; + + std::map entries; + }; + +} + +#endif diff --git a/src/lib/constructs/tss/info.txt b/src/lib/constructs/tss/info.txt new file mode 100644 index 000000000..0c86bebbe --- /dev/null +++ b/src/lib/constructs/tss/info.txt @@ -0,0 +1,8 @@ +define THRESHOLD_SECRET_SHARING 20131128 + + +hash +rng +filters +hex + diff --git a/src/lib/constructs/tss/tss.cpp b/src/lib/constructs/tss/tss.cpp new file mode 100644 index 000000000..2024b39ec --- /dev/null +++ b/src/lib/constructs/tss/tss.cpp @@ -0,0 +1,262 @@ +/* +* RTSS (threshold secret sharing) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/** +Table for GF(2^8) arithmetic (exponentials) +*/ +const byte RTSS_EXP[256] = { +0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, +0x96, 0xA1, 0xF8, 0x13, 0x35, 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, +0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA, 0xE5, +0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, +0x90, 0xAB, 0xE6, 0x31, 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, +0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD, 0x4C, 0xD4, +0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, +0x28, 0x78, 0x88, 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, +0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A, 0xB5, 0xC4, 0x57, +0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, +0x61, 0xA3, 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, +0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0, 0xFB, 0x16, 0x3A, 0x4E, +0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, +0x41, 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, +0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75, 0x9F, 0xBA, 0xD5, 0x64, 0xAC, +0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80, +0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, +0xB1, 0xC8, 0x43, 0xC5, 0x54, 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, +0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA, 0x45, +0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, +0xC6, 0x51, 0xF3, 0x0E, 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, +0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17, 0x39, 0x4B, +0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, +0x52, 0xF6, 0x01 }; + +/** +Table for GF(2^8) arithmetic (logarithms) +*/ +const byte RTSS_LOG[] = { +0x90, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, +0x68, 0x33, 0xEE, 0xDF, 0x03, 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, +0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1, 0x7D, +0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, +0x9A, 0xC9, 0x09, 0x78, 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, +0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E, 0x96, 0x8F, +0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, +0x46, 0x83, 0x38, 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, +0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10, 0x7E, 0x6E, 0x48, +0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, +0x3D, 0xBA, 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, +0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57, 0xAF, 0x58, 0xA8, 0x50, +0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, +0xE8, 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, +0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0, 0x7F, 0x0C, 0xF6, 0x6F, 0x17, +0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7, +0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, +0x6C, 0xAA, 0x55, 0x29, 0x9D, 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, +0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1, 0x53, +0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, +0x56, 0xF2, 0xD3, 0xAB, 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, +0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5, 0x67, 0x4A, +0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, +0xF7, 0x70, 0x07 }; + +byte gfp_mul(byte x, byte y) + { + if(x == 0 || y == 0) + return 0; + return RTSS_EXP[(RTSS_LOG[x] + RTSS_LOG[y]) % 255]; + } + +byte rtss_hash_id(const std::string& hash_name) + { + if(hash_name == "SHA-160") + return 1; + else if(hash_name == "SHA-256") + return 2; + else + throw Invalid_Argument("RTSS only supports SHA-1 and SHA-256"); + } + +HashFunction* get_rtss_hash_by_id(byte id) + { + if(id == 1) + return new SHA_160; + else if(id == 2) + return new SHA_256; + else + throw Decoding_Error("Bad RTSS hash identifier"); + } + +} + +RTSS_Share::RTSS_Share(const std::string& hex_input) + { + contents = hex_decode_locked(hex_input); + } + +byte RTSS_Share::share_id() const + { + if(!initialized()) + throw Invalid_State("RTSS_Share::share_id not initialized"); + + return contents[20]; + } + +std::string RTSS_Share::to_string() const + { + return hex_encode(&contents[0], contents.size()); + } + +std::vector +RTSS_Share::split(byte M, byte N, + const byte S[], u16bit S_len, + const byte identifier[16], + RandomNumberGenerator& rng) + { + if(M == 0 || N == 0 || M > N) + throw Encoding_Error("RTSS_Share::split: M == 0 or N == 0 or M > N"); + + SHA_256 hash; // always use SHA-256 when generating shares + + std::vector shares(N); + + // Create RTSS header in each share + for(byte i = 0; i != N; ++i) + { + shares[i].contents += std::make_pair(identifier, 16); + shares[i].contents += rtss_hash_id(hash.name()); + shares[i].contents += M; + shares[i].contents += get_byte(0, S_len); + shares[i].contents += get_byte(1, S_len); + } + + // Choose sequential values for X starting from 1 + for(byte i = 0; i != N; ++i) + shares[i].contents.push_back(i+1); + + // secret = S || H(S) + secure_vector secret(S, S + S_len); + secret += hash.process(S, S_len); + + for(size_t i = 0; i != secret.size(); ++i) + { + std::vector coefficients(M-1); + rng.randomize(&coefficients[0], coefficients.size()); + + for(byte j = 0; j != N; ++j) + { + const byte X = j + 1; + + byte sum = secret[i]; + byte X_i = X; + + for(size_t k = 0; k != coefficients.size(); ++k) + { + sum ^= gfp_mul(X_i, coefficients[k]); + X_i = gfp_mul(X_i, X); + } + + shares[j].contents.push_back(sum); + } + } + + return shares; + } + +secure_vector +RTSS_Share::reconstruct(const std::vector& shares) + { + const size_t RTSS_HEADER_SIZE = 20; + + for(size_t i = 0; i != shares.size(); ++i) + { + if(shares[i].size() != shares[0].size()) + throw Decoding_Error("Different sized RTSS shares detected"); + if(shares[i].share_id() == 0) + throw Decoding_Error("Invalid (id = 0) RTSS share detected"); + if(shares[i].size() < RTSS_HEADER_SIZE) + throw Decoding_Error("Missing or malformed RTSS header"); + + if(!same_mem(&shares[0].contents[0], + &shares[i].contents[0], RTSS_HEADER_SIZE)) + throw Decoding_Error("Different RTSS headers detected"); + } + + if(shares.size() < shares[0].contents[17]) + throw Decoding_Error("Insufficient shares to do TSS reconstruction"); + + u16bit secret_len = make_u16bit(shares[0].contents[18], + shares[0].contents[19]); + + byte hash_id = shares[0].contents[16]; + + std::unique_ptr hash(get_rtss_hash_by_id(hash_id)); + + if(shares[0].size() != secret_len + hash->output_length() + RTSS_HEADER_SIZE + 1) + throw Decoding_Error("Bad RTSS length field in header"); + + std::vector V(shares.size()); + secure_vector secret; + + for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i) + { + for(size_t j = 0; j != V.size(); ++j) + V[j] = shares[j].contents[i]; + + byte r = 0; + for(size_t k = 0; k != shares.size(); ++k) + { + // L_i function: + byte r2 = 1; + for(size_t l = 0; l != shares.size(); ++l) + { + if(k == l) + continue; + + byte share_k = shares[k].share_id(); + byte share_l = shares[l].share_id(); + + if(share_k == share_l) + throw Decoding_Error("Duplicate shares found in RTSS recovery"); + + byte div = RTSS_EXP[(255 + + RTSS_LOG[share_l] - + RTSS_LOG[share_k ^ share_l]) % 255]; + + r2 = gfp_mul(r2, div); + } + + r ^= gfp_mul(V[k], r2); + } + secret.push_back(r); + } + + if(secret.size() != secret_len + hash->output_length()) + throw Decoding_Error("Bad length in RTSS output"); + + hash->update(&secret[0], secret_len); + secure_vector hash_check = hash->final(); + + if(!same_mem(&hash_check[0], + &secret[secret_len], hash->output_length())) + throw Decoding_Error("RTSS hash check failed"); + + return secure_vector(&secret[0], &secret[secret_len]); + } + +} diff --git a/src/lib/constructs/tss/tss.h b/src/lib/constructs/tss/tss.h new file mode 100644 index 000000000..4664af317 --- /dev/null +++ b/src/lib/constructs/tss/tss.h @@ -0,0 +1,76 @@ +/* +* RTSS (threshold secret sharing) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RTSS_H__ +#define BOTAN_RTSS_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* A split secret, using the format from draft-mcgrew-tss-03 +*/ +class BOTAN_DLL RTSS_Share + { + public: + /** + * @param M the number of shares needed to reconstruct + * @param N the number of shares generated + * @param secret the secret to split + * @param secret_len the length of the secret + * @param identifier the 16 byte share identifier + * @param rng the random number generator to use + */ + static std::vector + split(byte M, byte N, + const byte secret[], u16bit secret_len, + const byte identifier[16], + RandomNumberGenerator& rng); + + /** + * @param shares the list of shares + */ + static secure_vector + reconstruct(const std::vector& shares); + + RTSS_Share() {} + + /** + * @param hex_input the share encoded in hexadecimal + */ + RTSS_Share(const std::string& hex_input); + + /** + * @return hex representation + */ + std::string to_string() const; + + /** + * @return share identifier + */ + byte share_id() const; + + /** + * @return size of this share in bytes + */ + size_t size() const { return contents.size(); } + + /** + * @return if this TSS share was initialized or not + */ + bool initialized() const { return (contents.size() > 0); } + private: + secure_vector contents; + }; + +} + +#endif diff --git a/src/lib/credentials/credentials_manager.cpp b/src/lib/credentials/credentials_manager.cpp new file mode 100644 index 000000000..1077edf61 --- /dev/null +++ b/src/lib/credentials/credentials_manager.cpp @@ -0,0 +1,135 @@ +/* +* Credentials Manager +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +std::string Credentials_Manager::psk_identity_hint(const std::string&, + const std::string&) + { + return ""; + } + +std::string Credentials_Manager::psk_identity(const std::string&, + const std::string&, + const std::string&) + { + return ""; + } + +SymmetricKey Credentials_Manager::psk(const std::string&, + const std::string&, + const std::string& identity) + { + throw Internal_Error("No PSK set for identity " + identity); + } + +bool Credentials_Manager::attempt_srp(const std::string&, + const std::string&) + { + return false; + } + +std::string Credentials_Manager::srp_identifier(const std::string&, + const std::string&) + { + return ""; + } + +std::string Credentials_Manager::srp_password(const std::string&, + const std::string&, + const std::string&) + { + return ""; + } + +bool Credentials_Manager::srp_verifier(const std::string&, + const std::string&, + const std::string&, + std::string&, + BigInt&, + std::vector&, + bool) + { + return false; + } + +std::vector Credentials_Manager::cert_chain( + const std::vector&, + const std::string&, + const std::string&) + { + return std::vector(); + } + +std::vector Credentials_Manager::cert_chain_single_type( + const std::string& cert_key_type, + const std::string& type, + const std::string& context) + { + std::vector cert_types; + cert_types.push_back(cert_key_type); + return cert_chain(cert_types, type, context); + } + +Private_Key* Credentials_Manager::private_key_for(const X509_Certificate&, + const std::string&, + const std::string&) + { + return nullptr; + } + +std::vector +Credentials_Manager::trusted_certificate_authorities( + const std::string&, + const std::string&) + { + return std::vector(); + } + +namespace { + +bool cert_in_some_store(const std::vector& trusted_CAs, + const X509_Certificate& trust_root) + { + for(auto CAs : trusted_CAs) + if(CAs->certificate_known(trust_root)) + return true; + return false; + } + +} + +void Credentials_Manager::verify_certificate_chain( + const std::string& type, + const std::string& purported_hostname, + const std::vector& cert_chain) + { + if(cert_chain.empty()) + throw std::invalid_argument("Certificate chain was empty"); + + auto trusted_CAs = trusted_certificate_authorities(type, purported_hostname); + + Path_Validation_Restrictions restrictions; + + auto result = x509_path_validate(cert_chain, + restrictions, + trusted_CAs); + + if(!result.successful_validation()) + throw std::runtime_error("Certificate validation failure: " + result.result_string()); + + if(!cert_in_some_store(trusted_CAs, result.trust_root())) + throw std::runtime_error("Certificate chain roots in unknown/untrusted CA"); + + if(purported_hostname != "" && !cert_chain[0].matches_dns_name(purported_hostname)) + throw std::runtime_error("Certificate did not match hostname"); + } + +} diff --git a/src/lib/credentials/credentials_manager.h b/src/lib/credentials/credentials_manager.h new file mode 100644 index 000000000..85db078e3 --- /dev/null +++ b/src/lib/credentials/credentials_manager.h @@ -0,0 +1,189 @@ +/* +* Credentials Manager +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CREDENTIALS_MANAGER_H__ +#define BOTAN_CREDENTIALS_MANAGER_H__ + +#include +#include +#include +#include + +namespace Botan { + +class BigInt; + +/** +* Interface for a credentials manager. +* +* A type is a fairly static value that represents the general nature +* of the transaction occuring. Currently used values are "tls-client" +* and "tls-server". Context represents a hostname, email address, +* username, or other identifier. +*/ +class BOTAN_DLL Credentials_Manager + { + public: + virtual ~Credentials_Manager() {} + + /** + * Return a list of the certificates of CAs that we trust in this + * type/context. + * + * @param type specifies the type of operation occuring + * + * @param context specifies a context relative to type. For instance + * for type "tls-client", context specifies the servers name. + */ + virtual std::vector trusted_certificate_authorities( + const std::string& type, + const std::string& context); + + /** + * Check the certificate chain is valid up to a trusted root, and + * optionally (if hostname != "") that the hostname given is + * consistent with the leaf certificate. + * + * This function should throw an exception derived from + * std::exception with an informative what() result if the + * certificate chain cannot be verified. + + * @param type specifies the type of operation occuring + * @param hostname specifies the purported hostname + * @param cert_chain specifies a certificate chain leading to a + * trusted root CA certificate. + */ + virtual void verify_certificate_chain( + const std::string& type, + const std::string& hostname, + const std::vector& cert_chain); + + /** + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. + * + * It is assumed that the caller can get the private key of the + * leaf with private_key_for + * + * @param cert_key_types specifies the key types desired ("RSA", + * "DSA", "ECDSA", etc), or empty if there + * is no preference by the caller. + * + * @param type specifies the type of operation occuring + * + * @param context specifies a context relative to type. + */ + virtual std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& type, + const std::string& context); + + /** + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. + * + * It is assumed that the caller can get the private key of the + * leaf with private_key_for + * + * @param cert_key_type specifies the type of key requested + * ("RSA", "DSA", "ECDSA", etc) + * + * @param type specifies the type of operation occuring + * + * @param context specifies a context relative to type. + */ + std::vector cert_chain_single_type( + const std::string& cert_key_type, + const std::string& type, + const std::string& context); + + /** + * @return private key associated with this certificate if we should + * use it with this context. cert was returned by cert_chain + * @note this object should retain ownership of the returned key; + * it should not be deleted by the caller. + */ + virtual Private_Key* private_key_for(const X509_Certificate& cert, + const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occuring + * @param context specifies a context relative to type. + * @return true if we should attempt SRP authentication + */ + virtual bool attempt_srp(const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occuring + * @param context specifies a context relative to type. + * @return identifier for client-side SRP auth, if available + for this type/context. Should return empty string + if password auth not desired/available. + */ + virtual std::string srp_identifier(const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occuring + * @param context specifies a context relative to type. + * @param identifier specifies what identifier we want the + * password for. This will be a value previously returned + * by srp_identifier. + * @return password for client-side SRP auth, if available + for this identifier/type/context. + */ + virtual std::string srp_password(const std::string& type, + const std::string& context, + const std::string& identifier); + + /** + * Retrieve SRP verifier parameters + */ + virtual bool srp_verifier(const std::string& type, + const std::string& context, + const std::string& identifier, + std::string& group_name, + BigInt& verifier, + std::vector& salt, + bool generate_fake_on_unknown); + + /** + * @param type specifies the type of operation occuring + * @param context specifies a context relative to type. + * @return the PSK identity hint for this type/context + */ + virtual std::string psk_identity_hint(const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occuring + * @param context specifies a context relative to type. + * @param identity_hint was passed by the server (but may be empty) + * @return the PSK identity we want to use + */ + virtual std::string psk_identity(const std::string& type, + const std::string& context, + const std::string& identity_hint); + + /** + * @param type specifies the type of operation occuring + * @param context specifies a context relative to type. + * @param identity is a PSK identity previously returned by + psk_identity for the same type and context. + * @return the PSK used for identity, or throw an exception if no + * key exists + */ + virtual SymmetricKey psk(const std::string& type, + const std::string& context, + const std::string& identity); + }; + +} + +#endif diff --git a/src/lib/credentials/info.txt b/src/lib/credentials/info.txt new file mode 100644 index 000000000..303139c4c --- /dev/null +++ b/src/lib/credentials/info.txt @@ -0,0 +1,5 @@ +define CREDENTIALS_MANAGER 20131128 + + +x509 + diff --git a/src/lib/engine/aes_isa_eng/aes_isa_engine.cpp b/src/lib/engine/aes_isa_eng/aes_isa_engine.cpp new file mode 100644 index 000000000..956a1ce38 --- /dev/null +++ b/src/lib/engine/aes_isa_eng/aes_isa_engine.cpp @@ -0,0 +1,36 @@ +/* +* Engine for AES instructions +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if defined(BOTAN_HAS_AES_NI) + #include +#endif + +namespace Botan { + +BlockCipher* +AES_ISA_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + if(request.algo_name() == "AES-128") + return new AES_128_NI; + if(request.algo_name() == "AES-192") + return new AES_192_NI; + if(request.algo_name() == "AES-256") + return new AES_256_NI; + } +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/aes_isa_eng/aes_isa_engine.h b/src/lib/engine/aes_isa_eng/aes_isa_engine.h new file mode 100644 index 000000000..3c4d3e936 --- /dev/null +++ b/src/lib/engine/aes_isa_eng/aes_isa_engine.h @@ -0,0 +1,30 @@ +/* +* Engine for AES instructions +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_ISA_ENGINE_H__ +#define BOTAN_AES_ISA_ENGINE_H__ + +#include + +namespace Botan { + +/** +* Engine for implementations that hook into CPU-specific +* AES implementations (eg AES-NI, VIA C7, or AMD Geode) +*/ +class AES_ISA_Engine : public Engine + { + public: + std::string provider_name() const { return "aes_isa"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + }; + +} + +#endif diff --git a/src/lib/engine/aes_isa_eng/info.txt b/src/lib/engine/aes_isa_eng/info.txt new file mode 100644 index 000000000..4284e75bd --- /dev/null +++ b/src/lib/engine/aes_isa_eng/info.txt @@ -0,0 +1,11 @@ +define ENGINE_AES_ISA 20131128 + +load_on dep + + +aes_isa_engine.cpp + + + +aes_isa_engine.h + diff --git a/src/lib/engine/asm_engine/asm_engine.cpp b/src/lib/engine/asm_engine/asm_engine.cpp new file mode 100644 index 000000000..a43a3302d --- /dev/null +++ b/src/lib/engine/asm_engine/asm_engine.cpp @@ -0,0 +1,72 @@ +/* +* Assembly Implementation Engine +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_HAS_SERPENT_X86_32) + #include +#endif + +#if defined(BOTAN_HAS_MD4_X86_32) + #include +#endif + +#if defined(BOTAN_HAS_MD5_X86_32) + #include +#endif + +#if defined(BOTAN_HAS_SHA1_X86_64) + #include +#endif + +#if defined(BOTAN_HAS_SHA1_X86_32) + #include +#endif + +namespace Botan { + +BlockCipher* +Assembler_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { + if(request.algo_name() == "Serpent") + { +#if defined(BOTAN_HAS_SERPENT_X86_32) + return new Serpent_X86_32; +#endif + } + + return nullptr; + } + +HashFunction* +Assembler_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_MD4_X86_32) + if(request.algo_name() == "MD4") + return new MD4_X86_32; +#endif + +#if defined(BOTAN_HAS_MD5_X86_32) + if(request.algo_name() == "MD5") + return new MD5_X86_32; +#endif + + if(request.algo_name() == "SHA-160") + { +#if defined(BOTAN_HAS_SHA1_X86_64) + return new SHA_160_X86_64; +#elif defined(BOTAN_HAS_SHA1_X86_32) + return new SHA_160_X86_32; +#endif + } + + return nullptr; + } + +} diff --git a/src/lib/engine/asm_engine/asm_engine.h b/src/lib/engine/asm_engine/asm_engine.h new file mode 100644 index 000000000..40fe5342f --- /dev/null +++ b/src/lib/engine/asm_engine/asm_engine.h @@ -0,0 +1,32 @@ +/* +* Assembly Implementation Engine +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X86_32_ASM_ENGINE_H__ +#define BOTAN_X86_32_ASM_ENGINE_H__ + +#include + +namespace Botan { + +/** +* Engine for x86-32 specific implementations +*/ +class Assembler_Engine : public Engine + { + public: + std::string provider_name() const { return "asm"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const; + }; + +} + +#endif diff --git a/src/lib/engine/asm_engine/info.txt b/src/lib/engine/asm_engine/info.txt new file mode 100644 index 000000000..185656e3d --- /dev/null +++ b/src/lib/engine/asm_engine/info.txt @@ -0,0 +1,11 @@ +define ENGINE_ASSEMBLER 20131128 + +load_on dep + + +asm_engine.cpp + + + +asm_engine.h + diff --git a/src/lib/engine/core_engine/core_engine.h b/src/lib/engine/core_engine/core_engine.h new file mode 100644 index 000000000..ca660d21b --- /dev/null +++ b/src/lib/engine/core_engine/core_engine.h @@ -0,0 +1,71 @@ +/* +* Core Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CORE_ENGINE_H__ +#define BOTAN_CORE_ENGINE_H__ + +#include + +namespace Botan { + +/** +* Core Engine +*/ +class Core_Engine : public Engine + { + public: + std::string provider_name() const override { return "core"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + Modular_Exponentiator* mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const override; + + Keyed_Filter* get_cipher(const std::string&, Cipher_Dir, + Algorithm_Factory&); + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + StreamCipher* find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const override; + + MessageAuthenticationCode* find_mac(const SCAN_Name& request, + Algorithm_Factory&) const override; + + PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override; + }; + +/** +* Create a cipher mode filter object +* @param block_cipher a block cipher object +* @param direction are we encrypting or decrypting? +* @param mode the name of the cipher mode to use +* @param padding the mode padding to use (only used for ECB, CBC) +*/ +Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, + Cipher_Dir direction, + const std::string& mode, + const std::string& padding); + +} + +#endif diff --git a/src/lib/engine/core_engine/core_modes.cpp b/src/lib/engine/core_engine/core_modes.cpp new file mode 100644 index 000000000..6524d9c16 --- /dev/null +++ b/src/lib/engine/core_engine/core_modes.cpp @@ -0,0 +1,279 @@ +/* +* Core Engine +* (C) 1999-2007,2011,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_MODE_CFB) + #include +#endif + +#if defined(BOTAN_HAS_MODE_ECB) + #include +#endif + +#if defined(BOTAN_HAS_MODE_CBC) + #include +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + #include +#endif + +#if defined(BOTAN_HAS_OFB) + #include +#endif + +#if defined(BOTAN_HAS_CTR_BE) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_FILTER) + +#include + +#if defined(BOTAN_HAS_AEAD_CCM) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + #include +#endif + +#endif + +namespace Botan { + +namespace { + +/** +* Get a block cipher padding method by name +*/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec, + const std::string& def_if_empty) + { +#if defined(BOTAN_HAS_CIPHER_MODE_PADDING) + if(algo_spec == "NoPadding" || (algo_spec == "" && def_if_empty == "NoPadding")) + return new Null_Padding; + + if(algo_spec == "PKCS7" || (algo_spec == "" && def_if_empty == "PKCS7")) + return new PKCS7_Padding; + + if(algo_spec == "OneAndZeros") + return new OneAndZeros_Padding; + + if(algo_spec == "X9.23") + return new ANSI_X923_Padding; + +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +} + +Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, + Cipher_Dir direction, + const std::string& mode, + const std::string& padding) + { +#if defined(BOTAN_HAS_OFB) + if(mode == "OFB") + return new StreamCipher_Filter(new OFB(block_cipher->clone())); +#endif + +#if defined(BOTAN_HAS_CTR_BE) + if(mode == "CTR-BE") + return new StreamCipher_Filter(new CTR_BE(block_cipher->clone())); +#endif + +#if defined(BOTAN_HAS_MODE_ECB) + if(mode == "ECB" || mode == "") + { + if(direction == ENCRYPTION) + return new Transformation_Filter( + new ECB_Encryption(block_cipher->clone(), get_bc_pad(padding, "NoPadding"))); + else + return new Transformation_Filter( + new ECB_Decryption(block_cipher->clone(), get_bc_pad(padding, "NoPadding"))); + } +#endif + + if(mode == "CBC") + { +#if defined(BOTAN_HAS_MODE_CBC) + if(padding == "CTS") + { + if(direction == ENCRYPTION) + return new Transformation_Filter(new CTS_Encryption(block_cipher->clone())); + else + return new Transformation_Filter(new CTS_Decryption(block_cipher->clone())); + } + + if(direction == ENCRYPTION) + return new Transformation_Filter( + new CBC_Encryption(block_cipher->clone(), get_bc_pad(padding, "PKCS7"))); + else + return new Transformation_Filter( + new CBC_Decryption(block_cipher->clone(), get_bc_pad(padding, "PKCS7"))); +#else + return nullptr; +#endif + } + +#if defined(BOTAN_HAS_MODE_XTS) + if(mode == "XTS") + { + if(direction == ENCRYPTION) + return new Transformation_Filter(new XTS_Encryption(block_cipher->clone())); + else + return new Transformation_Filter(new XTS_Decryption(block_cipher->clone())); + } +#endif + + if(mode.find("CFB") != std::string::npos || + mode.find("EAX") != std::string::npos || + mode.find("GCM") != std::string::npos || + mode.find("OCB") != std::string::npos || + mode.find("CCM") != std::string::npos) + { + std::vector algo_info = parse_algorithm_name(mode); + const std::string mode_name = algo_info[0]; + + size_t bits = 8 * block_cipher->block_size(); + if(algo_info.size() > 1) + bits = to_u32bit(algo_info[1]); + +#if defined(BOTAN_HAS_MODE_CFB) + if(mode_name == "CFB") + { + if(direction == ENCRYPTION) + return new Transformation_Filter(new CFB_Encryption(block_cipher->clone(), bits)); + else + return new Transformation_Filter(new CFB_Decryption(block_cipher->clone(), bits)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_FILTER) + + if(bits % 8 != 0) + throw std::invalid_argument("AEAD interface does not support non-octet length tags"); + + const size_t tag_size = bits / 8; + +#if defined(BOTAN_HAS_AEAD_CCM) + if(mode_name == "CCM") + { + const size_t L = (algo_info.size() == 3) ? to_u32bit(algo_info[2]) : 3; + if(direction == ENCRYPTION) + return new AEAD_Filter(new CCM_Encryption(block_cipher->clone(), tag_size, L)); + else + return new AEAD_Filter(new CCM_Decryption(block_cipher->clone(), tag_size, L)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + if(mode_name == "EAX") + { + if(direction == ENCRYPTION) + return new AEAD_Filter(new EAX_Encryption(block_cipher->clone(), tag_size)); + else + return new AEAD_Filter(new EAX_Decryption(block_cipher->clone(), tag_size)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + if(mode_name == "OCB") + { + if(direction == ENCRYPTION) + return new AEAD_Filter(new OCB_Encryption(block_cipher->clone(), tag_size)); + else + return new AEAD_Filter(new OCB_Decryption(block_cipher->clone(), tag_size)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + if(mode_name == "GCM") + { + if(direction == ENCRYPTION) + return new AEAD_Filter(new GCM_Encryption(block_cipher->clone(), tag_size)); + else + return new AEAD_Filter(new GCM_Decryption(block_cipher->clone(), tag_size)); + } +#endif + +#endif + } + + return nullptr; + } + +/* +* Get a cipher object +*/ +Keyed_Filter* Core_Engine::get_cipher(const std::string& algo_spec, + Cipher_Dir direction, + Algorithm_Factory& af) + { + std::vector algo_parts = split_on(algo_spec, '/'); + if(algo_parts.empty()) + throw Invalid_Algorithm_Name(algo_spec); + + const std::string cipher_name = algo_parts[0]; + + // check if it is a stream cipher first (easy case) + const StreamCipher* stream_cipher = af.prototype_stream_cipher(cipher_name); + if(stream_cipher) + return new StreamCipher_Filter(stream_cipher->clone()); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_name); + if(!block_cipher) + return nullptr; + + if(algo_parts.size() >= 4) + return nullptr; // 4 part mode, not something we know about + + if(algo_parts.size() < 2) + throw Lookup_Error("Cipher specification '" + algo_spec + + "' is missing mode identifier"); + + std::string mode = algo_parts[1]; + + std::string padding; + if(algo_parts.size() == 3) + padding = algo_parts[2]; + else + padding = (mode == "CBC") ? "PKCS7" : "NoPadding"; + + if(mode == "ECB" && padding == "CTS") + return nullptr; + else if((mode != "CBC" && mode != "ECB") && padding != "NoPadding") + throw Invalid_Algorithm_Name(algo_spec); + + Keyed_Filter* filt = get_cipher_mode(block_cipher, direction, mode, padding); + if(filt) + return filt; + + if(padding != "NoPadding") + throw Algorithm_Not_Found(cipher_name + "/" + mode + "/" + padding); + else + throw Algorithm_Not_Found(cipher_name + "/" + mode); + } + +} diff --git a/src/lib/engine/core_engine/def_pk_ops.cpp b/src/lib/engine/core_engine/def_pk_ops.cpp new file mode 100644 index 000000000..e99945633 --- /dev/null +++ b/src/lib/engine/core_engine/def_pk_ops.cpp @@ -0,0 +1,170 @@ +/* +* PK Operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_HAS_RSA) + #include +#endif + +#if defined(BOTAN_HAS_RW) + #include +#endif + +#if defined(BOTAN_HAS_DSA) + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + #include +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + #include +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include +#endif + +#if defined(BOTAN_HAS_ECDH) + #include +#endif + +namespace Botan { + +PK_Ops::Encryption* +Core_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(const ElGamal_PublicKey* s = dynamic_cast(&key)) + return new ElGamal_Encryption_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Decryption* +Core_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new RSA_Private_Operation(*s, rng); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(const ElGamal_PrivateKey* s = dynamic_cast(&key)) + return new ElGamal_Decryption_Operation(*s, rng); +#endif + + return nullptr; + } + +PK_Ops::Key_Agreement* +Core_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast(&key)) + return new DH_KA_Operation(*dh, rng); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(const ECDH_PrivateKey* ecdh = dynamic_cast(&key)) + return new ECDH_KA_Operation(*ecdh); +#endif + + return nullptr; + } + +PK_Ops::Signature* +Core_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new RSA_Private_Operation(*s, rng); +#endif + +#if defined(BOTAN_HAS_RW) + if(const RW_PrivateKey* s = dynamic_cast(&key)) + return new RW_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast(&key)) + return new DSA_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(const ECDSA_PrivateKey* s = dynamic_cast(&key)) + return new ECDSA_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(const GOST_3410_PrivateKey* s = + dynamic_cast(&key)) + return new GOST_3410_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(const NR_PrivateKey* s = dynamic_cast(&key)) + return new NR_Signature_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Verification* +Core_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_RW) + if(const RW_PublicKey* s = dynamic_cast(&key)) + return new RW_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast(&key)) + return new DSA_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(const ECDSA_PublicKey* s = dynamic_cast(&key)) + return new ECDSA_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(const GOST_3410_PublicKey* s = + dynamic_cast(&key)) + return new GOST_3410_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(const NR_PublicKey* s = dynamic_cast(&key)) + return new NR_Verification_Operation(*s); +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/core_engine/def_powm.cpp b/src/lib/engine/core_engine/def_powm.cpp new file mode 100644 index 000000000..56a4b6844 --- /dev/null +++ b/src/lib/engine/core_engine/def_powm.cpp @@ -0,0 +1,24 @@ +/* +* Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Choose a modular exponentation algorithm +*/ +Modular_Exponentiator* +Core_Engine::mod_exp(const BigInt& n, Power_Mod::Usage_Hints hints) const + { + if(n.is_odd()) + return new Montgomery_Exponentiator(n, hints); + return new Fixed_Window_Exponentiator(n, hints); + } + +} diff --git a/src/lib/engine/core_engine/info.txt b/src/lib/engine/core_engine/info.txt new file mode 100644 index 000000000..44843e26a --- /dev/null +++ b/src/lib/engine/core_engine/info.txt @@ -0,0 +1,24 @@ +define CORE_ENGINE 20131128 + + +core_engine.h + + + +core_modes.cpp +def_pk_ops.cpp +def_powm.cpp +lookup_block.cpp +lookup_hash.cpp +lookup_mac.cpp +lookup_stream.cpp +lookup_pbkdf.cpp + + + +algo_factory +filters +libstate +mode_pad +numbertheory + diff --git a/src/lib/engine/core_engine/lookup_block.cpp b/src/lib/engine/core_engine/lookup_block.cpp new file mode 100644 index 000000000..0a9c02311 --- /dev/null +++ b/src/lib/engine/core_engine/lookup_block.cpp @@ -0,0 +1,298 @@ +/* +* Block Cipher Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_AES) + #include +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + #include +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + #include +#endif + +#if defined(BOTAN_HAS_CAST) + #include + #include +#endif + +#if defined(BOTAN_HAS_CASCADE) + #include +#endif + +#if defined(BOTAN_HAS_DES) + #include + #include +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) + #include +#endif + +#if defined(BOTAN_HAS_IDEA) + #include +#endif + +#if defined(BOTAN_HAS_KASUMI) + #include +#endif + +#if defined(BOTAN_HAS_LION) + #include +#endif + +#if defined(BOTAN_HAS_LUBY_RACKOFF) + #include +#endif + +#if defined(BOTAN_HAS_MARS) + #include +#endif + +#if defined(BOTAN_HAS_MISTY1) + #include +#endif + +#if defined(BOTAN_HAS_NOEKEON) + #include +#endif + +#if defined(BOTAN_HAS_RC2) + #include +#endif + +#if defined(BOTAN_HAS_RC5) + #include +#endif + +#if defined(BOTAN_HAS_RC6) + #include +#endif + +#if defined(BOTAN_HAS_SAFER) + #include +#endif + +#if defined(BOTAN_HAS_SEED) + #include +#endif + +#if defined(BOTAN_HAS_SERPENT) + #include +#endif + +#if defined(BOTAN_HAS_SKIPJACK) + #include +#endif + +#if defined(BOTAN_HAS_SQUARE) + #include +#endif + +#if defined(BOTAN_HAS_TEA) + #include +#endif + +#if defined(BOTAN_HAS_TWOFISH) + #include +#endif + +#if defined(BOTAN_HAS_THREEFISH_512) + #include +#endif + +#if defined(BOTAN_HAS_XTEA) + #include +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +BlockCipher* Core_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory& af) const + { + +#if defined(BOTAN_HAS_AES) + if(request.algo_name() == "AES-128") + return new AES_128; + if(request.algo_name() == "AES-192") + return new AES_192; + if(request.algo_name() == "AES-256") + return new AES_256; +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + if(request.algo_name() == "Blowfish") + return new Blowfish; +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + if(request.algo_name() == "Camellia-128") + return new Camellia_128; + if(request.algo_name() == "Camellia-192") + return new Camellia_192; + if(request.algo_name() == "Camellia-256") + return new Camellia_256; +#endif + +#if defined(BOTAN_HAS_CAST) + if(request.algo_name() == "CAST-128") + return new CAST_128; + if(request.algo_name() == "CAST-256") + return new CAST_256; +#endif + +#if defined(BOTAN_HAS_DES) + if(request.algo_name() == "DES") + return new DES; + if(request.algo_name() == "DESX") + return new DESX; + if(request.algo_name() == "TripleDES") + return new TripleDES; +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) + if(request.algo_name() == "GOST-28147-89") + return new GOST_28147_89(request.arg(0, "R3411_94_TestParam")); +#endif + +#if defined(BOTAN_HAS_IDEA) + if(request.algo_name() == "IDEA") + return new IDEA; +#endif + +#if defined(BOTAN_HAS_KASUMI) + if(request.algo_name() == "KASUMI") + return new KASUMI; +#endif + +#if defined(BOTAN_HAS_MARS) + if(request.algo_name() == "MARS") + return new MARS; +#endif + +#if defined(BOTAN_HAS_MISTY1) + if(request.algo_name() == "MISTY1") + return new MISTY1(request.arg_as_integer(0, 8)); +#endif + +#if defined(BOTAN_HAS_NOEKEON) + if(request.algo_name() == "Noekeon") + return new Noekeon; +#endif + +#if defined(BOTAN_HAS_RC2) + if(request.algo_name() == "RC2") + return new RC2; +#endif + +#if defined(BOTAN_HAS_RC5) + if(request.algo_name() == "RC5") + return new RC5(request.arg_as_integer(0, 12)); +#endif + +#if defined(BOTAN_HAS_RC6) + if(request.algo_name() == "RC6") + return new RC6; +#endif + +#if defined(BOTAN_HAS_SAFER) + if(request.algo_name() == "SAFER-SK") + return new SAFER_SK(request.arg_as_integer(0, 10)); +#endif + +#if defined(BOTAN_HAS_SEED) + if(request.algo_name() == "SEED") + return new SEED; +#endif + +#if defined(BOTAN_HAS_SERPENT) + if(request.algo_name() == "Serpent") + return new Serpent; +#endif + +#if defined(BOTAN_HAS_SKIPJACK) + if(request.algo_name() == "Skipjack") + return new Skipjack; +#endif + +#if defined(BOTAN_HAS_SQUARE) + if(request.algo_name() == "Square") + return new Square; +#endif + +#if defined(BOTAN_HAS_TEA) + if(request.algo_name() == "TEA") + return new TEA; +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(request.algo_name() == "Twofish") + return new Twofish; +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(request.algo_name() == "Threefish-512") + return new Threefish_512; +#endif + +#if defined(BOTAN_HAS_XTEA) + if(request.algo_name() == "XTEA") + return new XTEA; +#endif + +#if defined(BOTAN_HAS_LUBY_RACKOFF) + if(request.algo_name() == "Luby-Rackoff" && request.arg_count() == 1) + { + const HashFunction* hash = af.prototype_hash_function(request.arg(0)); + + if(hash) + return new LubyRackoff(hash->clone()); + } +#endif + +#if defined(BOTAN_HAS_CASCADE) + if(request.algo_name() == "Cascade" && request.arg_count() == 2) + { + const BlockCipher* c1 = af.prototype_block_cipher(request.arg(0)); + const BlockCipher* c2 = af.prototype_block_cipher(request.arg(1)); + + if(c1 && c2) + return new Cascade_Cipher(c1->clone(), c2->clone()); + } +#endif + +#if defined(BOTAN_HAS_LION) + if(request.algo_name() == "Lion" && request.arg_count_between(2, 3)) + { + const size_t block_size = request.arg_as_integer(2, 1024); + + const HashFunction* hash = + af.prototype_hash_function(request.arg(0)); + + const StreamCipher* stream_cipher = + af.prototype_stream_cipher(request.arg(1)); + + if(!hash || !stream_cipher) + return nullptr; + + return new Lion(hash->clone(), stream_cipher->clone(), block_size); + } +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/core_engine/lookup_hash.cpp b/src/lib/engine/core_engine/lookup_hash.cpp new file mode 100644 index 000000000..7a9a0148d --- /dev/null +++ b/src/lib/engine/core_engine/lookup_hash.cpp @@ -0,0 +1,238 @@ +/* +* Hash Algorithms Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_ADLER32) + #include +#endif + +#if defined(BOTAN_HAS_CRC24) + #include +#endif + +#if defined(BOTAN_HAS_CRC32) + #include +#endif + +#if defined(BOTAN_HAS_BMW_512) + #include +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + #include +#endif + +#if defined(BOTAN_HAS_HAS_160) + #include +#endif + +#if defined(BOTAN_HAS_KECCAK) + #include +#endif + +#if defined(BOTAN_HAS_MD2) + #include +#endif + +#if defined(BOTAN_HAS_MD4) + #include +#endif + +#if defined(BOTAN_HAS_MD5) + #include +#endif + +#if defined(BOTAN_HAS_RIPEMD_128) + #include +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + #include +#endif + +#if defined(BOTAN_HAS_SHA1) + #include +#endif + +#if defined(BOTAN_HAS_SHA2_32) + #include +#endif + +#if defined(BOTAN_HAS_SHA2_64) + #include +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + #include +#endif + +#if defined(BOTAN_HAS_TIGER) + #include +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + #include +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + #include +#endif + +#if defined(BOTAN_HAS_COMB4P) + #include +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +HashFunction* Core_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory& af) const + { +#if defined(BOTAN_HAS_ADLER32) + if(request.algo_name() == "Adler32") + return new Adler32; +#endif + +#if defined(BOTAN_HAS_CRC24) + if(request.algo_name() == "CRC24") + return new CRC24; +#endif + +#if defined(BOTAN_HAS_CRC32) + if(request.algo_name() == "CRC32") + return new CRC32; +#endif + +#if defined(BOTAN_HAS_BMW_512) + if(request.algo_name() == "BMW-512") + return new BMW_512; +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + if(request.algo_name() == "GOST-R-34.11-94") + return new GOST_34_11; +#endif + +#if defined(BOTAN_HAS_HAS_160) + if(request.algo_name() == "HAS-160") + return new HAS_160; +#endif + +#if defined(BOTAN_HAS_KECCAK) + if(request.algo_name() == "Keccak-1600") + return new Keccak_1600(request.arg_as_integer(0, 512)); +#endif + +#if defined(BOTAN_HAS_MD2) + if(request.algo_name() == "MD2") + return new MD2; +#endif + +#if defined(BOTAN_HAS_MD4) + if(request.algo_name() == "MD4") + return new MD4; +#endif + +#if defined(BOTAN_HAS_MD5) + if(request.algo_name() == "MD5") + return new MD5; +#endif + +#if defined(BOTAN_HAS_RIPEMD_128) + if(request.algo_name() == "RIPEMD-128") + return new RIPEMD_128; +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + if(request.algo_name() == "RIPEMD-160") + return new RIPEMD_160; +#endif + +#if defined(BOTAN_HAS_SHA1) + if(request.algo_name() == "SHA-160") + return new SHA_160; +#endif + +#if defined(BOTAN_HAS_SHA2_32) + if(request.algo_name() == "SHA-224") + return new SHA_224; + if(request.algo_name() == "SHA-256") + return new SHA_256; +#endif + +#if defined(BOTAN_HAS_SHA2_64) + if(request.algo_name() == "SHA-384") + return new SHA_384; + if(request.algo_name() == "SHA-512") + return new SHA_512; +#endif + +#if defined(BOTAN_HAS_TIGER) + if(request.algo_name() == "Tiger") + return new Tiger(request.arg_as_integer(0, 24), // hash output + request.arg_as_integer(1, 3)); // # passes +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + if(request.algo_name() == "Skein-512") + return new Skein_512(request.arg_as_integer(0, 512), + request.arg(1, "")); +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(request.algo_name() == "Whirlpool") + return new Whirlpool; +#endif + +#if defined(BOTAN_HAS_COMB4P) + if(request.algo_name() == "Comb4P" && request.arg_count() == 2) + { + const HashFunction* h1 = af.prototype_hash_function(request.arg(0)); + const HashFunction* h2 = af.prototype_hash_function(request.arg(1)); + + if(h1 && h2) + return new Comb4P(h1->clone(), h2->clone()); + } +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + + if(request.algo_name() == "Parallel") + { + std::vector hash_prototypes; + + /* First pass, just get the prototypes (no memory allocation). Then + if all were found, replace each prototype with a newly created clone + */ + for(size_t i = 0; i != request.arg_count(); ++i) + { + const HashFunction* hash = af.prototype_hash_function(request.arg(i)); + if(!hash) + return nullptr; + + hash_prototypes.push_back(hash); + } + + std::vector hashes; + for(size_t i = 0; i != hash_prototypes.size(); ++i) + hashes.push_back(hash_prototypes[i]->clone()); + + return new Parallel(hashes); + } + +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/core_engine/lookup_mac.cpp b/src/lib/engine/core_engine/lookup_mac.cpp new file mode 100644 index 000000000..32275b559 --- /dev/null +++ b/src/lib/engine/core_engine/lookup_mac.cpp @@ -0,0 +1,70 @@ +/* +* MAC Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_CBC_MAC) + #include +#endif + +#if defined(BOTAN_HAS_CMAC) + #include +#endif + +#if defined(BOTAN_HAS_HMAC) + #include +#endif + +#if defined(BOTAN_HAS_SSL3_MAC) + #include +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + #include +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +MessageAuthenticationCode* +Core_Engine::find_mac(const SCAN_Name& request, + Algorithm_Factory& af) const + { + +#if defined(BOTAN_HAS_CBC_MAC) + if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1) + return new CBC_MAC(af.make_block_cipher(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_CMAC) + if(request.algo_name() == "CMAC" && request.arg_count() == 1) + return new CMAC(af.make_block_cipher(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_HMAC) + if(request.algo_name() == "HMAC" && request.arg_count() == 1) + return new HMAC(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_SSL3_MAC) + if(request.algo_name() == "SSL3-MAC" && request.arg_count() == 1) + return new SSL3_MAC(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + if(request.algo_name() == "X9.19-MAC" && request.arg_count() == 0) + return new ANSI_X919_MAC(af.make_block_cipher("DES")); +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/core_engine/lookup_pbkdf.cpp b/src/lib/engine/core_engine/lookup_pbkdf.cpp new file mode 100644 index 000000000..bfd2c8bc2 --- /dev/null +++ b/src/lib/engine/core_engine/lookup_pbkdf.cpp @@ -0,0 +1,43 @@ +/* +* PBKDF Lookup +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_PBKDF1) + #include +#endif + +#if defined(BOTAN_HAS_PBKDF2) + #include +#endif + +namespace Botan { + +PBKDF* Core_Engine::find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { +#if defined(BOTAN_HAS_PBKDF1) + if(algo_spec.algo_name() == "PBKDF1" && algo_spec.arg_count() == 1) + return new PKCS5_PBKDF1(af.make_hash_function(algo_spec.arg(0))); +#endif + +#if defined(BOTAN_HAS_PBKDF2) + if(algo_spec.algo_name() == "PBKDF2" && algo_spec.arg_count() == 1) + { + if(const MessageAuthenticationCode* mac_proto = af.prototype_mac(algo_spec.arg(0))) + return new PKCS5_PBKDF2(mac_proto->clone()); + + return new PKCS5_PBKDF2(af.make_mac("HMAC(" + algo_spec.arg(0) + ")")); + } +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/core_engine/lookup_stream.cpp b/src/lib/engine/core_engine/lookup_stream.cpp new file mode 100644 index 000000000..b26bbedcd --- /dev/null +++ b/src/lib/engine/core_engine/lookup_stream.cpp @@ -0,0 +1,43 @@ +/* +* Stream Cipher Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if defined(BOTAN_HAS_RC4) + #include +#endif + +#if defined(BOTAN_HAS_SALSA20) + #include +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +StreamCipher* +Core_Engine::find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_RC4) + if(request.algo_name() == "RC4") + return new RC4(request.arg_as_integer(0, 0)); + if(request.algo_name() == "RC4_drop") + return new RC4(768); +#endif + +#if defined(BOTAN_HAS_SALSA20) + if(request.algo_name() == "Salsa20") + return new Salsa20; +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/dyn_engine/dyn_engine.cpp b/src/lib/engine/dyn_engine/dyn_engine.cpp new file mode 100644 index 000000000..078ec4b83 --- /dev/null +++ b/src/lib/engine/dyn_engine/dyn_engine.cpp @@ -0,0 +1,63 @@ +/** +* Dynamically Loaded Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +extern "C" { + typedef Engine* (*creator_func)(void); + typedef u32bit (*module_version_func)(void); +} + +} + +Dynamically_Loaded_Engine::Dynamically_Loaded_Engine( + const std::string& library_path) : + engine(nullptr) + { + lib = new Dynamically_Loaded_Library(library_path); + + try + { + module_version_func get_version = + lib->resolve("module_version"); + + const u32bit mod_version = get_version(); + + if(mod_version != 20101003) + throw std::runtime_error("Incompatible version in " + + library_path + " of " + + std::to_string(mod_version)); + + creator_func creator = + lib->resolve("create_engine"); + + engine = creator(); + + if(!engine) + throw std::runtime_error("Creator function in " + + library_path + " failed"); + } + catch(...) + { + delete lib; + lib = nullptr; + throw; + } + } + +Dynamically_Loaded_Engine::~Dynamically_Loaded_Engine() + { + delete engine; + delete lib; + } + +} diff --git a/src/lib/engine/dyn_engine/dyn_engine.h b/src/lib/engine/dyn_engine/dyn_engine.h new file mode 100644 index 000000000..39e13ab36 --- /dev/null +++ b/src/lib/engine/dyn_engine/dyn_engine.h @@ -0,0 +1,115 @@ +/** +* Dynamically Loaded Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DYN_LOADED_ENGINE_H__ +#define BOTAN_DYN_LOADED_ENGINE_H__ + +#include + +namespace Botan { + +/** +* Dynamically_Loaded_Engine just proxies the requests to the underlying +* Engine object, and handles load/unload details +*/ +class BOTAN_DLL Dynamically_Loaded_Engine : public Engine + { + public: + /** + * @param lib_path full pathname to DLL to load + */ + Dynamically_Loaded_Engine(const std::string& lib_path); + + Dynamically_Loaded_Engine(const Dynamically_Loaded_Engine&) = delete; + + Dynamically_Loaded_Engine& operator=(const Dynamically_Loaded_Engine&) = delete; + + ~Dynamically_Loaded_Engine(); + + std::string provider_name() const override { return engine->provider_name(); } + + BlockCipher* find_block_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_block_cipher(algo_spec, af); + } + + StreamCipher* find_stream_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_stream_cipher(algo_spec, af); + } + + HashFunction* find_hash(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_hash(algo_spec, af); + } + + MessageAuthenticationCode* find_mac(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_mac(algo_spec, af); + } + + PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_pbkdf(algo_spec, af); + } + + Modular_Exponentiator* mod_exp(const BigInt& n, + Power_Mod::Usage_Hints hints) const override + { + return engine->mod_exp(n, hints); + } + + Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir dir, + Algorithm_Factory& af) + { + return engine->get_cipher(algo_spec, dir, af); + } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_key_agreement_op(key, rng); + } + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_signature_op(key, rng); + } + + PK_Ops::Verification* + get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_verify_op(key, rng); + } + + PK_Ops::Encryption* + get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_encryption_op(key, rng); + } + + PK_Ops::Decryption* + get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_decryption_op(key, rng); + } + + private: + class Dynamically_Loaded_Library* lib; + Engine* engine; + }; + +} + +#endif diff --git a/src/lib/engine/dyn_engine/info.txt b/src/lib/engine/dyn_engine/info.txt new file mode 100644 index 000000000..54379f501 --- /dev/null +++ b/src/lib/engine/dyn_engine/info.txt @@ -0,0 +1,14 @@ +define DYNAMICALLY_LOADED_ENGINE 20131128 + + +dyn_engine.h + + + +dyn_engine.cpp + + + +engine +dyn_load + diff --git a/src/lib/engine/engine.cpp b/src/lib/engine/engine.cpp new file mode 100644 index 000000000..a50f1e7b2 --- /dev/null +++ b/src/lib/engine/engine.cpp @@ -0,0 +1,91 @@ +/* +* Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +BlockCipher* +Engine::find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +StreamCipher* +Engine::find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +HashFunction* +Engine::find_hash(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +MessageAuthenticationCode* +Engine::find_mac(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +PBKDF* +Engine::find_pbkdf(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +Modular_Exponentiator* +Engine::mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const + { + return nullptr; + } + +Keyed_Filter* Engine::get_cipher(const std::string&, + Cipher_Dir, + Algorithm_Factory&) + { + return nullptr; + } + +PK_Ops::Key_Agreement* +Engine::get_key_agreement_op(const Private_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Signature* +Engine::get_signature_op(const Private_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Verification* +Engine::get_verify_op(const Public_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Encryption* +Engine::get_encryption_op(const Public_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Decryption* +Engine::get_decryption_op(const Private_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +} diff --git a/src/lib/engine/engine.h b/src/lib/engine/engine.h new file mode 100644 index 000000000..a03a6e1ec --- /dev/null +++ b/src/lib/engine/engine.h @@ -0,0 +1,150 @@ +/* +* Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_H__ +#define BOTAN_ENGINE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class Algorithm_Factory; +class Keyed_Filter; +class RandomNumberGenerator; + +/** +* Base class for all engines. All non-pure virtual functions simply +* return NULL, indicating the algorithm in question is not +* supported. Subclasses can reimplement whichever function(s) +* they want to hook in a particular type. +*/ +class BOTAN_DLL Engine + { + public: + virtual ~Engine() {} + + /** + * @return name of this engine + */ + virtual std::string provider_name() const = 0; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual BlockCipher* + find_block_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual StreamCipher* + find_stream_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual HashFunction* + find_hash(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual MessageAuthenticationCode* + find_mac(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param n the modulus + * @param hints any use hints + * @return newly allocated object, or NULL + */ + virtual Modular_Exponentiator* + mod_exp(const BigInt& n, + Power_Mod::Usage_Hints hints) const; + + /** + * Return a new cipher object + * @param algo_spec the algorithm name/specification + * @param dir specifies if encryption or decryption is desired + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir dir, + Algorithm_Factory& af); + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Verification* + get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Encryption* + get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Decryption* + get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const; + }; + +} + +#endif diff --git a/src/lib/engine/gnump/gmp_mem.cpp b/src/lib/engine/gnump/gmp_mem.cpp new file mode 100644 index 000000000..b5a5a303e --- /dev/null +++ b/src/lib/engine/gnump/gmp_mem.cpp @@ -0,0 +1,83 @@ +/* +* GNU MP Memory Handlers +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* For keeping track of existing GMP_Engines and only +* resetting the memory when none are in use. +*/ +std::atomic gmp_alloc_refcnt(0); + +/* +* Allocation Function for GNU MP +*/ +void* gmp_malloc(size_t n) + { + // Maintain alignment, mlock goes for sizeof(T) alignment + if(n % 8 == 0) + return secure_allocator().allocate(n / 8); + else if(n % 4 == 0) + return secure_allocator().allocate(n / 4); + else if(n % 2 == 0) + return secure_allocator().allocate(n / 2); + + return secure_allocator().allocate(n); + } + +/* +* Deallocation Function for GNU MP +*/ +void gmp_free(void* ptr, size_t n) + { + secure_allocator().deallocate(static_cast(ptr), n); + } + +/* +* Reallocation Function for GNU MP +*/ +void* gmp_realloc(void* ptr, size_t old_n, size_t new_n) + { + void* new_buf = gmp_malloc(new_n); + std::memcpy(new_buf, ptr, std::min(old_n, new_n)); + gmp_free(ptr, old_n); + return new_buf; + } + +} + +/* +* GMP_Engine Constructor +*/ +GMP_Engine::GMP_Engine() + { + /* + if(gmp_alloc_refcnt == 0) + mp_set_memory_functions(gmp_malloc, gmp_realloc, gmp_free); + + gmp_alloc_refcnt++; + */ + } + +GMP_Engine::~GMP_Engine() + { + /* + --gmp_alloc_refcnt; + + if(gmp_alloc_refcnt == 0) + mp_set_memory_functions(NULL, NULL, NULL); + */ + } + +} diff --git a/src/lib/engine/gnump/gmp_powm.cpp b/src/lib/engine/gnump/gmp_powm.cpp new file mode 100644 index 000000000..70c2b2f5e --- /dev/null +++ b/src/lib/engine/gnump/gmp_powm.cpp @@ -0,0 +1,53 @@ +/* +* GMP Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* GMP Modular Exponentiator +*/ +class GMP_Modular_Exponentiator : public Modular_Exponentiator + { + public: + void set_base(const BigInt& b) { base = b; } + void set_exponent(const BigInt& e) { exp = e; } + BigInt execute() const; + Modular_Exponentiator* copy() const + { return new GMP_Modular_Exponentiator(*this); } + + GMP_Modular_Exponentiator(const BigInt& n) : mod(n) {} + private: + GMP_MPZ base, exp, mod; + }; + +/* +* Compute the result +*/ +BigInt GMP_Modular_Exponentiator::execute() const + { + GMP_MPZ r; + mpz_powm(r.value, base.value, exp.value, mod.value); + return r.to_bigint(); + } + +} + +/* +* Return the GMP-based modular exponentiator +*/ +Modular_Exponentiator* GMP_Engine::mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const + { + return new GMP_Modular_Exponentiator(n); + } + +} diff --git a/src/lib/engine/gnump/gmp_wrap.cpp b/src/lib/engine/gnump/gmp_wrap.cpp new file mode 100644 index 000000000..974593d02 --- /dev/null +++ b/src/lib/engine/gnump/gmp_wrap.cpp @@ -0,0 +1,101 @@ +/* +* GMP Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#define GNU_MP_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +#define GNU_MP_VERSION_CODE \ + GNU_MP_VERSION_CODE_FOR(__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, \ + __GNU_MP_VERSION_PATCHLEVEL) + +#if GNU_MP_VERSION_CODE < GNU_MP_VERSION_CODE_FOR(4,1,0) + #error Your GNU MP install is too old, upgrade to 4.1 or later +#endif + +namespace Botan { + +/* +* GMP_MPZ Constructor +*/ +GMP_MPZ::GMP_MPZ(const BigInt& in) + { + mpz_init(value); + if(in != 0) + mpz_import(value, in.sig_words(), -1, sizeof(word), 0, 0, in.data()); + } + +/* +* GMP_MPZ Constructor +*/ +GMP_MPZ::GMP_MPZ(const byte in[], size_t length) + { + mpz_init(value); + mpz_import(value, length, 1, 1, 0, 0, in); + } + +/* +* GMP_MPZ Copy Constructor +*/ +GMP_MPZ::GMP_MPZ(const GMP_MPZ& other) + { + mpz_init_set(value, other.value); + } + +/* +* GMP_MPZ Destructor +*/ +GMP_MPZ::~GMP_MPZ() + { + mpz_clear(value); + } + +/* +* GMP_MPZ Assignment Operator +*/ +GMP_MPZ& GMP_MPZ::operator=(const GMP_MPZ& other) + { + mpz_set(value, other.value); + return (*this); + } + +/* +* Export the mpz_t as a bytestring +*/ +void GMP_MPZ::encode(byte out[], size_t length) const + { + size_t dummy = 0; + mpz_export(out + (length - bytes()), &dummy, 1, 1, 0, 0, value); + } + +/* +* Return the number of significant bytes +*/ +size_t GMP_MPZ::bytes() const + { + return ((mpz_sizeinbase(value, 2) + 7) / 8); + } + +/* +* GMP to BigInt Conversions +*/ +BigInt GMP_MPZ::to_bigint() const + { + BigInt out(BigInt::Positive, (bytes() + sizeof(word) - 1) / sizeof(word)); + size_t dummy = 0; + + word* reg = out.mutable_data(); + + mpz_export(reg, &dummy, -1, sizeof(word), 0, 0, value); + + if(mpz_sgn(value) < 0) + out.flip_sign(); + + return out; + } + +} diff --git a/src/lib/engine/gnump/gmp_wrap.h b/src/lib/engine/gnump/gmp_wrap.h new file mode 100644 index 000000000..291d65a01 --- /dev/null +++ b/src/lib/engine/gnump/gmp_wrap.h @@ -0,0 +1,41 @@ +/* +* GMP MPZ Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GMP_MPZ_WRAP_H__ +#define BOTAN_GMP_MPZ_WRAP_H__ + +#include +#include + +namespace Botan { + +/** +* Lightweight GMP mpz_t wrapper. For internal use only. +*/ +class GMP_MPZ + { + public: + mpz_t value; + + BigInt to_bigint() const; + void encode(byte[], size_t) const; + size_t bytes() const; + + secure_vector to_bytes() const + { return BigInt::encode_locked(to_bigint()); } + + GMP_MPZ& operator=(const GMP_MPZ&); + + GMP_MPZ(const GMP_MPZ&); + GMP_MPZ(const BigInt& = 0); + GMP_MPZ(const byte[], size_t); + ~GMP_MPZ(); + }; + +} + +#endif diff --git a/src/lib/engine/gnump/gnump_engine.h b/src/lib/engine/gnump/gnump_engine.h new file mode 100644 index 000000000..ccc723514 --- /dev/null +++ b/src/lib/engine/gnump/gnump_engine.h @@ -0,0 +1,44 @@ +/* +* GMP Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_GMP_H__ +#define BOTAN_ENGINE_GMP_H__ + +#include + +namespace Botan { + +/** +* Engine using GNU MP +*/ +class GMP_Engine : public Engine + { + public: + GMP_Engine(); + ~GMP_Engine(); + + std::string provider_name() const override { return "gmp"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const override; + + Modular_Exponentiator* mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const override; + }; + +} + +#endif diff --git a/src/lib/engine/gnump/gnump_pk.cpp b/src/lib/engine/gnump/gnump_pk.cpp new file mode 100644 index 000000000..29e172d47 --- /dev/null +++ b/src/lib/engine/gnump/gnump_pk.cpp @@ -0,0 +1,338 @@ +/* +* GnuMP PK operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +/* GnuMP 5.0 and later have a side-channel resistent powm */ +#if defined(HAVE_MPZ_POWM_SEC) + #undef mpz_powm + #define mpz_powm mpz_powm_sec +#endif + +#if defined(BOTAN_HAS_RSA) + #include +#endif + +#if defined(BOTAN_HAS_DSA) + #include +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +class GMP_DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + GMP_DH_KA_Operation(const DH_PrivateKey& dh) : + x(dh.get_x()), p(dh.group_p()) {} + + secure_vector agree(const byte w[], size_t w_len) + { + GMP_MPZ z(w, w_len); + mpz_powm(z.value, z.value, x.value, p.value); + return z.to_bytes(); + } + + private: + GMP_MPZ x, p; + }; +#endif + +#if defined(BOTAN_HAS_DSA) + +class GMP_DSA_Signature_Operation : public PK_Ops::Signature + { + public: + GMP_DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + x(dsa.get_x()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const GMP_MPZ x, p, q, g; + size_t q_bits; + }; + +secure_vector +GMP_DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t q_bytes = (q_bits + 7) / 8; + + rng.add_entropy(msg, msg_len); + + BigInt k_bn; + do + k_bn.randomize(rng, q_bits); + while(k_bn >= q.to_bigint()); + + GMP_MPZ i(msg, msg_len); + GMP_MPZ k(k_bn); + + GMP_MPZ r; + mpz_powm(r.value, g.value, k.value, p.value); + mpz_mod(r.value, r.value, q.value); + + mpz_invert(k.value, k.value, q.value); + + GMP_MPZ s; + mpz_mul(s.value, x.value, r.value); + mpz_add(s.value, s.value, i.value); + mpz_mul(s.value, s.value, k.value); + mpz_mod(s.value, s.value, q.value); + + if(mpz_cmp_ui(r.value, 0) == 0 || mpz_cmp_ui(s.value, 0) == 0) + throw Internal_Error("GMP_DSA_Op::sign: r or s was zero"); + + secure_vector output(2*q_bytes); + r.encode(&output[0], q_bytes); + s.encode(&output[q_bytes], q_bytes); + return output; + } + +class GMP_DSA_Verification_Operation : public PK_Ops::Verification + { + public: + GMP_DSA_Verification_Operation(const DSA_PublicKey& dsa) : + y(dsa.get_y()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const GMP_MPZ y, p, q, g; + size_t q_bits; + }; + +bool GMP_DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + GMP_MPZ r(sig, q_bytes); + GMP_MPZ s(sig + q_bytes, q_bytes); + GMP_MPZ i(msg, msg_len); + + if(mpz_cmp_ui(r.value, 0) <= 0 || mpz_cmp(r.value, q.value) >= 0) + return false; + if(mpz_cmp_ui(s.value, 0) <= 0 || mpz_cmp(s.value, q.value) >= 0) + return false; + + if(mpz_invert(s.value, s.value, q.value) == 0) + return false; + + GMP_MPZ si; + mpz_mul(si.value, s.value, i.value); + mpz_mod(si.value, si.value, q.value); + mpz_powm(si.value, g.value, si.value, p.value); + + GMP_MPZ sr; + mpz_mul(sr.value, s.value, r.value); + mpz_mod(sr.value, sr.value, q.value); + mpz_powm(sr.value, y.value, sr.value, p.value); + + mpz_mul(si.value, si.value, sr.value); + mpz_mod(si.value, si.value, p.value); + mpz_mod(si.value, si.value, q.value); + + if(mpz_cmp(si.value, r.value) == 0) + return true; + return false; + } + +#endif + +#if defined(BOTAN_HAS_RSA) + +class GMP_RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + GMP_RSA_Private_Operation(const RSA_PrivateKey& rsa) : + mod(rsa.get_n()), + p(rsa.get_p()), + q(rsa.get_q()), + d1(rsa.get_d1()), + d2(rsa.get_d2()), + c(rsa.get_c()), + n_bits(rsa.get_n().bits()) + {} + + size_t max_input_bits() const { return (n_bits - 1); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + BigInt x = private_op(m); + return BigInt::encode_1363(x, (n_bits + 7) / 8); + } + + secure_vector decrypt(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(private_op(m)); + } + + private: + BigInt private_op(const BigInt& m) const; + + GMP_MPZ mod, p, q, d1, d2, c; + size_t n_bits; + }; + +BigInt GMP_RSA_Private_Operation::private_op(const BigInt& m) const + { + GMP_MPZ j1, j2, h(m); + + mpz_powm(j1.value, h.value, d1.value, p.value); + mpz_powm(j2.value, h.value, d2.value, q.value); + mpz_sub(h.value, j1.value, j2.value); + mpz_mul(h.value, h.value, c.value); + mpz_mod(h.value, h.value, p.value); + mpz_mul(h.value, h.value, q.value); + mpz_add(h.value, h.value, j2.value); + return h.to_bigint(); + } + +class GMP_RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + GMP_RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), e(rsa.get_e()), mod(rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + secure_vector verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + + GMP_MPZ m_gmp(m); + mpz_powm(m_gmp.value, m_gmp.value, e.value, mod.value); + return m_gmp.to_bigint(); + } + + const BigInt& n; + const GMP_MPZ e, mod; + }; + +#endif + +} + +PK_Ops::Key_Agreement* +GMP_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast(&key)) + return new GMP_DH_KA_Operation(*dh); +#endif + + return nullptr; + } + +PK_Ops::Signature* +GMP_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new GMP_RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast(&key)) + return new GMP_DSA_Signature_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Verification* +GMP_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new GMP_RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast(&key)) + return new GMP_DSA_Verification_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Encryption* +GMP_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new GMP_RSA_Public_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Decryption* +GMP_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new GMP_RSA_Private_Operation(*s); +#endif + + return nullptr; + } + +} diff --git a/src/lib/engine/gnump/info.txt b/src/lib/engine/gnump/info.txt new file mode 100644 index 000000000..ad03339e4 --- /dev/null +++ b/src/lib/engine/gnump/info.txt @@ -0,0 +1,23 @@ +define ENGINE_GNU_MP 20131128 + +load_on request + + +all -> gmp + + + +gnump_engine.h +gmp_wrap.h + + + +gmp_mem.cpp +gmp_powm.cpp +gmp_wrap.cpp +gnump_pk.cpp + + + +bigint + diff --git a/src/lib/engine/info.txt b/src/lib/engine/info.txt new file mode 100644 index 000000000..800a007a1 --- /dev/null +++ b/src/lib/engine/info.txt @@ -0,0 +1,20 @@ +define ENGINES 20131128 + + +engine.h + + + +engine.cpp + + + +block +hash +libstate +mac +numbertheory +pbkdf +pubkey +stream + diff --git a/src/lib/engine/openssl/bn_powm.cpp b/src/lib/engine/openssl/bn_powm.cpp new file mode 100644 index 000000000..ac06fbe77 --- /dev/null +++ b/src/lib/engine/openssl/bn_powm.cpp @@ -0,0 +1,54 @@ +/* +* OpenSSL Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* OpenSSL Modular Exponentiator +*/ +class OpenSSL_Modular_Exponentiator : public Modular_Exponentiator + { + public: + void set_base(const BigInt& b) { base = b; } + void set_exponent(const BigInt& e) { exp = e; } + BigInt execute() const; + Modular_Exponentiator* copy() const + { return new OpenSSL_Modular_Exponentiator(*this); } + + OpenSSL_Modular_Exponentiator(const BigInt& n) : mod(n) {} + private: + OSSL_BN base, exp, mod; + OSSL_BN_CTX ctx; + }; + +/* +* Compute the result +*/ +BigInt OpenSSL_Modular_Exponentiator::execute() const + { + OSSL_BN r; + BN_mod_exp(r.ptr(), base.ptr(), exp.ptr(), mod.ptr(), ctx.ptr()); + return r.to_bigint(); + } + +} + +/* +* Return the OpenSSL-based modular exponentiator +*/ +Modular_Exponentiator* OpenSSL_Engine::mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const + { + return new OpenSSL_Modular_Exponentiator(n); + } + +} diff --git a/src/lib/engine/openssl/bn_wrap.cpp b/src/lib/engine/openssl/bn_wrap.cpp new file mode 100644 index 000000000..0a7e42368 --- /dev/null +++ b/src/lib/engine/openssl/bn_wrap.cpp @@ -0,0 +1,116 @@ +/* +* OpenSSL BN Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* OSSL_BN Constructor +*/ +OSSL_BN::OSSL_BN(const BigInt& in) + { + m_bn = BN_new(); + secure_vector encoding = BigInt::encode_locked(in); + if(in != 0) + BN_bin2bn(&encoding[0], encoding.size(), m_bn); + } + +/* +* OSSL_BN Constructor +*/ +OSSL_BN::OSSL_BN(const byte in[], size_t length) + { + m_bn = BN_new(); + BN_bin2bn(in, length, m_bn); + } + +/* +* OSSL_BN Copy Constructor +*/ +OSSL_BN::OSSL_BN(const OSSL_BN& other) + { + m_bn = BN_dup(other.m_bn); + } + +/* +* OSSL_BN Destructor +*/ +OSSL_BN::~OSSL_BN() + { + BN_clear_free(m_bn); + } + +/* +* OSSL_BN Assignment Operator +*/ +OSSL_BN& OSSL_BN::operator=(const OSSL_BN& other) + { + BN_copy(m_bn, other.m_bn); + return (*this); + } + +/* +* Export the BIGNUM as a bytestring +*/ +void OSSL_BN::encode(byte out[], size_t length) const + { + BN_bn2bin(m_bn, out + (length - bytes())); + } + +/* +* Return the number of significant bytes +*/ +size_t OSSL_BN::bytes() const + { + return BN_num_bytes(m_bn); + } + +/* +* OpenSSL to BigInt Conversions +*/ +BigInt OSSL_BN::to_bigint() const + { + secure_vector out(bytes()); + BN_bn2bin(m_bn, &out[0]); + return BigInt::decode(out); + } + +/* +* OSSL_BN_CTX Constructor +*/ +OSSL_BN_CTX::OSSL_BN_CTX() + { + m_ctx = BN_CTX_new(); + } + +/* +* OSSL_BN_CTX Copy Constructor +*/ +OSSL_BN_CTX::OSSL_BN_CTX(const OSSL_BN_CTX&) + { + m_ctx = BN_CTX_new(); + } + +/* +* OSSL_BN_CTX Destructor +*/ +OSSL_BN_CTX::~OSSL_BN_CTX() + { + BN_CTX_free(m_ctx); + } + +/* +* OSSL_BN_CTX Assignment Operator +*/ +OSSL_BN_CTX& OSSL_BN_CTX::operator=(const OSSL_BN_CTX&) + { + m_ctx = BN_CTX_new(); + return (*this); + } + +} diff --git a/src/lib/engine/openssl/bn_wrap.h b/src/lib/engine/openssl/bn_wrap.h new file mode 100644 index 000000000..12bcec152 --- /dev/null +++ b/src/lib/engine/openssl/bn_wrap.h @@ -0,0 +1,60 @@ +/* +* OpenSSL BN Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OPENSSL_BN_WRAP_H__ +#define BOTAN_OPENSSL_BN_WRAP_H__ + +#include +#include + +namespace Botan { + +/** +* Lightweight OpenSSL BN wrapper. For internal use only. +*/ +class OSSL_BN + { + public: + BigInt to_bigint() const; + void encode(byte[], size_t) const; + size_t bytes() const; + + secure_vector to_bytes() const + { return BigInt::encode_locked(to_bigint()); } + + OSSL_BN& operator=(const OSSL_BN&); + + OSSL_BN(const OSSL_BN&); + OSSL_BN(const BigInt& = 0); + OSSL_BN(const byte[], size_t); + ~OSSL_BN(); + + BIGNUM* ptr() const { return m_bn; } + private: + BIGNUM* m_bn; + }; + +/** +* Lightweight OpenSSL BN_CTX wrapper. For internal use only. +*/ +class OSSL_BN_CTX + { + public: + OSSL_BN_CTX& operator=(const OSSL_BN_CTX&); + + OSSL_BN_CTX(); + OSSL_BN_CTX(const OSSL_BN_CTX&); + ~OSSL_BN_CTX(); + + BN_CTX* ptr() const { return m_ctx; } + private: + BN_CTX* m_ctx; + }; + +} + +#endif diff --git a/src/lib/engine/openssl/info.txt b/src/lib/engine/openssl/info.txt new file mode 100644 index 000000000..d500816d5 --- /dev/null +++ b/src/lib/engine/openssl/info.txt @@ -0,0 +1,25 @@ +define ENGINE_OPENSSL 20131128 + +load_on request + + +all -> crypto + + + +openssl_engine.h +bn_wrap.h + + + +bn_powm.cpp +bn_wrap.cpp +ossl_arc4.cpp +ossl_bc.cpp +ossl_md.cpp +ossl_pk.cpp + + + +bigint + diff --git a/src/lib/engine/openssl/openssl_engine.h b/src/lib/engine/openssl/openssl_engine.h new file mode 100644 index 000000000..90f315c00 --- /dev/null +++ b/src/lib/engine/openssl/openssl_engine.h @@ -0,0 +1,49 @@ +/* +* OpenSSL Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_OPENSSL_H__ +#define BOTAN_ENGINE_OPENSSL_H__ + +#include + +namespace Botan { + +/** +* OpenSSL Engine +*/ +class OpenSSL_Engine : public Engine + { + public: + std::string provider_name() const override { return "openssl"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + Modular_Exponentiator* mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const override; + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + StreamCipher* find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + HashFunction* find_hash(const SCAN_Name&, Algorithm_Factory&) const override; + }; + +} + +#endif diff --git a/src/lib/engine/openssl/ossl_arc4.cpp b/src/lib/engine/openssl/ossl_arc4.cpp new file mode 100644 index 000000000..0eb404af1 --- /dev/null +++ b/src/lib/engine/openssl/ossl_arc4.cpp @@ -0,0 +1,89 @@ +/* +* OpenSSL RC4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/** +* RC4 as implemented by OpenSSL +*/ +class RC4_OpenSSL : public StreamCipher + { + public: + void clear() { clear_mem(&state, 1); } + + std::string name() const; + StreamCipher* clone() const { return new RC4_OpenSSL(SKIP); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(1, 32); + } + + + RC4_OpenSSL(size_t s = 0) : SKIP(s) { clear(); } + ~RC4_OpenSSL() { clear(); } + private: + void cipher(const byte[], byte[], size_t); + void key_schedule(const byte[], size_t); + + const size_t SKIP; + RC4_KEY state; + }; + +/* +* Return the name of this type +*/ +std::string RC4_OpenSSL::name() const + { + if(SKIP == 0) return "RC4"; + if(SKIP == 256) return "MARK-4"; + else return "RC4_skip(" + std::to_string(SKIP) + ")"; + } + +/* +* RC4 Key Schedule +*/ +void RC4_OpenSSL::key_schedule(const byte key[], size_t length) + { + RC4_set_key(&state, length, key); + byte dummy = 0; + for(size_t i = 0; i != SKIP; ++i) + RC4(&state, 1, &dummy, &dummy); + } + +/* +* RC4 Encryption +*/ +void RC4_OpenSSL::cipher(const byte in[], byte out[], size_t length) + { + RC4(&state, length, in, out); + } + +} + +/** +* Look for an OpenSSL-supported stream cipher (RC4) +*/ +StreamCipher* +OpenSSL_Engine::find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { + if(request.algo_name() == "RC4") + return new RC4_OpenSSL(request.arg_as_integer(0, 0)); + if(request.algo_name() == "RC4_drop") + return new RC4_OpenSSL(768); + + return 0; + } + +} diff --git a/src/lib/engine/openssl/ossl_bc.cpp b/src/lib/engine/openssl/ossl_bc.cpp new file mode 100644 index 000000000..b3b509c36 --- /dev/null +++ b/src/lib/engine/openssl/ossl_bc.cpp @@ -0,0 +1,248 @@ +/* +* OpenSSL Block Cipher +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* EVP Block Cipher +*/ +class EVP_BlockCipher : public BlockCipher + { + public: + void clear(); + std::string name() const { return cipher_name; } + BlockCipher* clone() const; + + size_t block_size() const { return block_sz; } + + EVP_BlockCipher(const EVP_CIPHER*, const std::string&); + + EVP_BlockCipher(const EVP_CIPHER*, const std::string&, + size_t, size_t, size_t); + + Key_Length_Specification key_spec() const { return cipher_key_spec; } + + ~EVP_BlockCipher(); + private: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + void key_schedule(const byte[], size_t); + + size_t block_sz; + Key_Length_Specification cipher_key_spec; + std::string cipher_name; + mutable EVP_CIPHER_CTX encrypt, decrypt; + }; + +/* +* EVP Block Cipher Constructor +*/ +EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo, + const std::string& algo_name) : + block_sz(EVP_CIPHER_block_size(algo)), + cipher_key_spec(EVP_CIPHER_key_length(algo)), + cipher_name(algo_name) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in"); + + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +/* +* EVP Block Cipher Constructor +*/ +EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo, + const std::string& algo_name, + size_t key_min, size_t key_max, + size_t key_mod) : + block_sz(EVP_CIPHER_block_size(algo)), + cipher_key_spec(key_min, key_max, key_mod), + cipher_name(algo_name) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in"); + + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +/* +* EVP Block Cipher Destructor +*/ +EVP_BlockCipher::~EVP_BlockCipher() + { + EVP_CIPHER_CTX_cleanup(&encrypt); + EVP_CIPHER_CTX_cleanup(&decrypt); + } + +/* +* Encrypt a block +*/ +void EVP_BlockCipher::encrypt_n(const byte in[], byte out[], + size_t blocks) const + { + int out_len = 0; + EVP_EncryptUpdate(&encrypt, out, &out_len, in, blocks * block_sz); + } + +/* +* Decrypt a block +*/ +void EVP_BlockCipher::decrypt_n(const byte in[], byte out[], + size_t blocks) const + { + int out_len = 0; + EVP_DecryptUpdate(&decrypt, out, &out_len, in, blocks * block_sz); + } + +/* +* Set the key +*/ +void EVP_BlockCipher::key_schedule(const byte key[], size_t length) + { + secure_vector full_key(key, key + length); + + if(cipher_name == "TripleDES" && length == 16) + { + full_key += std::make_pair(key, 8); + } + else + if(EVP_CIPHER_CTX_set_key_length(&encrypt, length) == 0 || + EVP_CIPHER_CTX_set_key_length(&decrypt, length) == 0) + throw Invalid_Argument("EVP_BlockCipher: Bad key length for " + + cipher_name); + + if(cipher_name == "RC2") + { + EVP_CIPHER_CTX_ctrl(&encrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0); + EVP_CIPHER_CTX_ctrl(&decrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0); + } + + EVP_EncryptInit_ex(&encrypt, 0, 0, &full_key[0], 0); + EVP_DecryptInit_ex(&decrypt, 0, 0, &full_key[0], 0); + } + +/* +* Return a clone of this object +*/ +BlockCipher* EVP_BlockCipher::clone() const + { + return new EVP_BlockCipher(EVP_CIPHER_CTX_cipher(&encrypt), + cipher_name, + cipher_key_spec.minimum_keylength(), + cipher_key_spec.maximum_keylength(), + cipher_key_spec.keylength_multiple()); + } + +/* +* Clear memory of sensitive data +*/ +void EVP_BlockCipher::clear() + { + const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(&encrypt); + + EVP_CIPHER_CTX_cleanup(&encrypt); + EVP_CIPHER_CTX_cleanup(&decrypt); + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +} + +/* +* Look for an algorithm with this name +*/ +BlockCipher* +OpenSSL_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#define HANDLE_EVP_CIPHER(NAME, EVP) \ + if(request.algo_name() == NAME && request.arg_count() == 0) \ + return new EVP_BlockCipher(EVP, NAME); + +#define HANDLE_EVP_CIPHER_KEYLEN(NAME, EVP, MIN, MAX, MOD) \ + if(request.algo_name() == NAME && request.arg_count() == 0) \ + return new EVP_BlockCipher(EVP, NAME, MIN, MAX, MOD); + +#if !defined(OPENSSL_NO_AES) + /* + Using OpenSSL's AES causes crashes inside EVP on x86-64 with OpenSSL 0.9.8g + cause is unknown + */ + HANDLE_EVP_CIPHER("AES-128", EVP_aes_128_ecb()); + HANDLE_EVP_CIPHER("AES-192", EVP_aes_192_ecb()); + HANDLE_EVP_CIPHER("AES-256", EVP_aes_256_ecb()); +#endif + +#if !defined(OPENSSL_NO_DES) + HANDLE_EVP_CIPHER("DES", EVP_des_ecb()); + HANDLE_EVP_CIPHER_KEYLEN("TripleDES", EVP_des_ede3_ecb(), 16, 24, 8); +#endif + +#if !defined(OPENSSL_NO_BF) + HANDLE_EVP_CIPHER_KEYLEN("Blowfish", EVP_bf_ecb(), 1, 56, 1); +#endif + +#if !defined(OPENSSL_NO_CAST) + HANDLE_EVP_CIPHER_KEYLEN("CAST-128", EVP_cast5_ecb(), 1, 16, 1); +#endif + +#if !defined(OPENSSL_NO_CAMELLIA) + HANDLE_EVP_CIPHER("Camellia-128", EVP_camellia_128_ecb()); + HANDLE_EVP_CIPHER("Camellia-192", EVP_camellia_192_ecb()); + HANDLE_EVP_CIPHER("Camellia-256", EVP_camellia_256_ecb()); +#endif + +#if !defined(OPENSSL_NO_RC2) + HANDLE_EVP_CIPHER_KEYLEN("RC2", EVP_rc2_ecb(), 1, 32, 1); +#endif + +#if !defined(OPENSSL_NO_RC5) && 0 + if(request.algo_name() == "RC5") + if(request.arg_as_integer(0, 12) == 12) + return new EVP_BlockCipher(EVP_rc5_32_12_16_ecb(), + "RC5(12)", 1, 32, 1); +#endif + +#if !defined(OPENSSL_NO_IDEA) && 0 + HANDLE_EVP_CIPHER("IDEA", EVP_idea_ecb()); +#endif + +#if !defined(OPENSSL_NO_SEED) + HANDLE_EVP_CIPHER("SEED", EVP_seed_ecb()); +#endif + +#undef HANDLE_EVP_CIPHER +#undef HANDLE_EVP_CIPHER_KEYLEN + + return 0; + } + +} diff --git a/src/lib/engine/openssl/ossl_md.cpp b/src/lib/engine/openssl/ossl_md.cpp new file mode 100644 index 000000000..e09a68a8e --- /dev/null +++ b/src/lib/engine/openssl/ossl_md.cpp @@ -0,0 +1,150 @@ +/* +* OpenSSL Hash Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* EVP Hash Function +*/ +class EVP_HashFunction : public HashFunction + { + public: + void clear(); + std::string name() const { return algo_name; } + HashFunction* clone() const; + + size_t output_length() const + { + return EVP_MD_size(EVP_MD_CTX_md(&md)); + } + + size_t hash_block_size() const + { + return EVP_MD_block_size(EVP_MD_CTX_md(&md)); + } + + EVP_HashFunction(const EVP_MD*, const std::string&); + ~EVP_HashFunction(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + + std::string algo_name; + EVP_MD_CTX md; + }; + +/* +* Update an EVP Hash Calculation +*/ +void EVP_HashFunction::add_data(const byte input[], size_t length) + { + EVP_DigestUpdate(&md, input, length); + } + +/* +* Finalize an EVP Hash Calculation +*/ +void EVP_HashFunction::final_result(byte output[]) + { + EVP_DigestFinal_ex(&md, output, 0); + const EVP_MD* algo = EVP_MD_CTX_md(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Clear memory of sensitive data +*/ +void EVP_HashFunction::clear() + { + const EVP_MD* algo = EVP_MD_CTX_md(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Return a clone of this object +*/ +HashFunction* EVP_HashFunction::clone() const + { + const EVP_MD* algo = EVP_MD_CTX_md(&md); + return new EVP_HashFunction(algo, name()); + } + +/* +* Create an EVP hash function +*/ +EVP_HashFunction::EVP_HashFunction(const EVP_MD* algo, + const std::string& name) : + algo_name(name) + { + EVP_MD_CTX_init(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Destroy an EVP hash function +*/ +EVP_HashFunction::~EVP_HashFunction() + { + EVP_MD_CTX_cleanup(&md); + } + +} + +/* +* Look for an algorithm with this name +*/ +HashFunction* OpenSSL_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if !defined(OPENSSL_NO_SHA) + if(request.algo_name() == "SHA-160") + return new EVP_HashFunction(EVP_sha1(), "SHA-160"); +#endif + +#if !defined(OPENSSL_NO_SHA256) + if(request.algo_name() == "SHA-224") + return new EVP_HashFunction(EVP_sha224(), "SHA-224"); + if(request.algo_name() == "SHA-256") + return new EVP_HashFunction(EVP_sha256(), "SHA-256"); +#endif + +#if !defined(OPENSSL_NO_SHA512) + if(request.algo_name() == "SHA-384") + return new EVP_HashFunction(EVP_sha384(), "SHA-384"); + if(request.algo_name() == "SHA-512") + return new EVP_HashFunction(EVP_sha512(), "SHA-512"); +#endif + +#if !defined(OPENSSL_NO_MD2) + if(request.algo_name() == "MD2") + return new EVP_HashFunction(EVP_md2(), "MD2"); +#endif + +#if !defined(OPENSSL_NO_MD4) + if(request.algo_name() == "MD4") + return new EVP_HashFunction(EVP_md4(), "MD4"); +#endif + +#if !defined(OPENSSL_NO_MD5) + if(request.algo_name() == "MD5") + return new EVP_HashFunction(EVP_md5(), "MD5"); +#endif + +#if !defined(OPENSSL_NO_RIPEMD) + if(request.algo_name() == "RIPEMD-160") + return new EVP_HashFunction(EVP_ripemd160(), "RIPEMD-160"); +#endif + + return 0; + } + +} diff --git a/src/lib/engine/openssl/ossl_pk.cpp b/src/lib/engine/openssl/ossl_pk.cpp new file mode 100644 index 000000000..cbe03d7b3 --- /dev/null +++ b/src/lib/engine/openssl/ossl_pk.cpp @@ -0,0 +1,338 @@ +/* +* OpenSSL PK operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if defined(BOTAN_HAS_RSA) + #include +#endif + +#if defined(BOTAN_HAS_DSA) + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include + #include +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +class OSSL_DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + OSSL_DH_KA_Operation(const DH_PrivateKey& dh) : + x(dh.get_x()), p(dh.group_p()) {} + + secure_vector agree(const byte w[], size_t w_len) + { + OSSL_BN i(w, w_len), r; + BN_mod_exp(r.ptr(), i.ptr(), x.ptr(), p.ptr(), ctx.ptr()); + return r.to_bytes(); + } + + private: + const OSSL_BN x, p; + OSSL_BN_CTX ctx; + }; +#endif + +#if defined(BOTAN_HAS_DSA) + +class OSSL_DSA_Signature_Operation : public PK_Ops::Signature + { + public: + OSSL_DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + x(dsa.get_x()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const OSSL_BN x, p, q, g; + const OSSL_BN_CTX ctx; + size_t q_bits; + }; + +secure_vector +OSSL_DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t q_bytes = (q_bits + 7) / 8; + + rng.add_entropy(msg, msg_len); + + BigInt k_bn; + do + k_bn.randomize(rng, q_bits); + while(k_bn >= q.to_bigint()); + + OSSL_BN i(msg, msg_len); + OSSL_BN k(k_bn); + + OSSL_BN r; + BN_mod_exp(r.ptr(), g.ptr(), k.ptr(), p.ptr(), ctx.ptr()); + BN_nnmod(r.ptr(), r.ptr(), q.ptr(), ctx.ptr()); + + BN_mod_inverse(k.ptr(), k.ptr(), q.ptr(), ctx.ptr()); + + OSSL_BN s; + BN_mul(s.ptr(), x.ptr(), r.ptr(), ctx.ptr()); + BN_add(s.ptr(), s.ptr(), i.ptr()); + BN_mod_mul(s.ptr(), s.ptr(), k.ptr(), q.ptr(), ctx.ptr()); + + if(BN_is_zero(r.ptr()) || BN_is_zero(s.ptr())) + throw Internal_Error("OpenSSL_DSA_Op::sign: r or s was zero"); + + secure_vector output(2*q_bytes); + r.encode(&output[0], q_bytes); + s.encode(&output[q_bytes], q_bytes); + return output; + } + +class OSSL_DSA_Verification_Operation : public PK_Ops::Verification + { + public: + OSSL_DSA_Verification_Operation(const DSA_PublicKey& dsa) : + y(dsa.get_y()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const OSSL_BN y, p, q, g; + const OSSL_BN_CTX ctx; + size_t q_bits; + }; + +bool OSSL_DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + OSSL_BN r(sig, q_bytes); + OSSL_BN s(sig + q_bytes, q_bytes); + OSSL_BN i(msg, msg_len); + + if(BN_is_zero(r.ptr()) || BN_cmp(r.ptr(), q.ptr()) >= 0) + return false; + if(BN_is_zero(s.ptr()) || BN_cmp(s.ptr(), q.ptr()) >= 0) + return false; + + if(BN_mod_inverse(s.ptr(), s.ptr(), q.ptr(), ctx.ptr()) == 0) + return false; + + OSSL_BN si; + BN_mod_mul(si.ptr(), s.ptr(), i.ptr(), q.ptr(), ctx.ptr()); + BN_mod_exp(si.ptr(), g.ptr(), si.ptr(), p.ptr(), ctx.ptr()); + + OSSL_BN sr; + BN_mod_mul(sr.ptr(), s.ptr(), r.ptr(), q.ptr(), ctx.ptr()); + BN_mod_exp(sr.ptr(), y.ptr(), sr.ptr(), p.ptr(), ctx.ptr()); + + BN_mod_mul(si.ptr(), si.ptr(), sr.ptr(), p.ptr(), ctx.ptr()); + BN_nnmod(si.ptr(), si.ptr(), q.ptr(), ctx.ptr()); + + if(BN_cmp(si.ptr(), r.ptr()) == 0) + return true; + return false; + + return false; + } + +#endif + +#if defined(BOTAN_HAS_RSA) + +class OSSL_RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + OSSL_RSA_Private_Operation(const RSA_PrivateKey& rsa) : + mod(rsa.get_n()), + p(rsa.get_p()), + q(rsa.get_q()), + d1(rsa.get_d1()), + d2(rsa.get_d2()), + c(rsa.get_c()), + n_bits(rsa.get_n().bits()) + {} + + size_t max_input_bits() const { return (n_bits - 1); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + BigInt x = private_op(m); + return BigInt::encode_1363(x, (n_bits + 7) / 8); + } + + secure_vector decrypt(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(private_op(m)); + } + + private: + BigInt private_op(const BigInt& m) const; + + const OSSL_BN mod, p, q, d1, d2, c; + const OSSL_BN_CTX ctx; + size_t n_bits; + }; + +BigInt OSSL_RSA_Private_Operation::private_op(const BigInt& m) const + { + OSSL_BN j1, j2, h(m); + + BN_mod_exp(j1.ptr(), h.ptr(), d1.ptr(), p.ptr(), ctx.ptr()); + BN_mod_exp(j2.ptr(), h.ptr(), d2.ptr(), q.ptr(), ctx.ptr()); + BN_sub(h.ptr(), j1.ptr(), j2.ptr()); + BN_mod_mul(h.ptr(), h.ptr(), c.ptr(), p.ptr(), ctx.ptr()); + BN_mul(h.ptr(), h.ptr(), q.ptr(), ctx.ptr()); + BN_add(h.ptr(), h.ptr(), j2.ptr()); + return h.to_bigint(); + } + +class OSSL_RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + OSSL_RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), e(rsa.get_e()), mod(rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + secure_vector verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + + OSSL_BN m_bn(m), r; + BN_mod_exp(r.ptr(), m_bn.ptr(), e.ptr(), mod.ptr(), ctx.ptr()); + return r.to_bigint(); + } + + const BigInt& n; + const OSSL_BN e, mod; + const OSSL_BN_CTX ctx; + }; + +#endif + +} + +PK_Ops::Key_Agreement* +OpenSSL_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast(&key)) + return new OSSL_DH_KA_Operation(*dh); +#endif + + return 0; + } + +PK_Ops::Signature* +OpenSSL_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new OSSL_RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast(&key)) + return new OSSL_DSA_Signature_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Verification* +OpenSSL_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new OSSL_RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast(&key)) + return new OSSL_DSA_Verification_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Encryption* +OpenSSL_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new OSSL_RSA_Public_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Decryption* +OpenSSL_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new OSSL_RSA_Private_Operation(*s); +#endif + + return 0; + } + +} diff --git a/src/lib/engine/simd_engine/info.txt b/src/lib/engine/simd_engine/info.txt new file mode 100644 index 000000000..2063c9dfe --- /dev/null +++ b/src/lib/engine/simd_engine/info.txt @@ -0,0 +1,15 @@ +define ENGINE_SIMD 20131128 + +load_on dep + + +simd_engine.cpp + + + +simd_engine.h + + + +simd + diff --git a/src/lib/engine/simd_engine/simd_engine.cpp b/src/lib/engine/simd_engine/simd_engine.cpp new file mode 100644 index 000000000..75463a4b1 --- /dev/null +++ b/src/lib/engine/simd_engine/simd_engine.cpp @@ -0,0 +1,97 @@ +/* +* SIMD Engine +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_AES_SSSE3) + #include +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + #include +#endif + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + #include +#endif + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + #include +#endif + +#if defined(BOTAN_HAS_XTEA_SIMD) + #include +#endif + +#if defined(BOTAN_HAS_IDEA_SSE2) + #include +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) + #include +#endif + +namespace Botan { + +BlockCipher* +SIMD_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_AES_SSSE3) + if(request.algo_name() == "AES-128" && CPUID::has_ssse3()) + return new AES_128_SSSE3; + if(request.algo_name() == "AES-192" && CPUID::has_ssse3()) + return new AES_192_SSSE3; + if(request.algo_name() == "AES-256" && CPUID::has_ssse3()) + return new AES_256_SSSE3; +#endif + +#if defined(BOTAN_HAS_IDEA_SSE2) + if(request.algo_name() == "IDEA" && CPUID::has_sse2()) + return new IDEA_SSE2; +#endif + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(request.algo_name() == "Noekeon" && SIMD_32::enabled()) + return new Noekeon_SIMD; +#endif + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(request.algo_name() == "Threefish-512" && CPUID::has_avx2()) + return new Threefish_512_AVX2; +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(request.algo_name() == "Serpent" && SIMD_32::enabled()) + return new Serpent_SIMD; +#endif + +#if defined(BOTAN_HAS_XTEA_SIMD) + if(request.algo_name() == "XTEA" && SIMD_32::enabled()) + return new XTEA_SIMD; +#endif + + return nullptr; + } + +HashFunction* +SIMD_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_SHA1_SSE2) + if(request.algo_name() == "SHA-160" && CPUID::has_sse2()) + return new SHA_160_SSE2; +#endif + + BOTAN_UNUSED(request); + + return nullptr; + } + +} diff --git a/src/lib/engine/simd_engine/simd_engine.h b/src/lib/engine/simd_engine/simd_engine.h new file mode 100644 index 000000000..66c8886f1 --- /dev/null +++ b/src/lib/engine/simd_engine/simd_engine.h @@ -0,0 +1,32 @@ +/* +* SIMD Assembly Engine +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_ENGINE_H__ +#define BOTAN_SIMD_ENGINE_H__ + +#include + +namespace Botan { + +/** +* Engine for implementations that use some kind of SIMD +*/ +class SIMD_Engine : public Engine + { + public: + std::string provider_name() const { return "simd"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const; + }; + +} + +#endif diff --git a/src/lib/entropy/beos_stats/es_beos.cpp b/src/lib/entropy/beos_stats/es_beos.cpp new file mode 100644 index 000000000..e514eb121 --- /dev/null +++ b/src/lib/entropy/beos_stats/es_beos.cpp @@ -0,0 +1,63 @@ +/* +* BeOS EntropySource +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#include +#include +#include + +namespace Botan { + +/** +* BeOS entropy poll +*/ +void BeOS_EntropySource::poll(Entropy_Accumulator& accum) + { + system_info info_sys; + get_system_info(&info_sys); + accum.add(info_sys, 2); + + key_info info_key; // current state of the keyboard + get_key_info(&info_key); + accum.add(info_key, 0); + + team_info info_team; + int32 cookie_team = 0; + + while(get_next_team_info(&cookie_team, &info_team) == B_OK) + { + accum.add(info_team, 2); + + team_id id = info_team.team; + int32 cookie = 0; + + thread_info info_thr; + while(get_next_thread_info(id, &cookie, &info_thr) == B_OK) + accum.add(info_thr, 1); + + cookie = 0; + image_info info_img; + while(get_next_image_info(id, &cookie, &info_img) == B_OK) + accum.add(info_img, 1); + + cookie = 0; + sem_info info_sem; + while(get_next_sem_info(id, &cookie, &info_sem) == B_OK) + accum.add(info_sem, 1); + + cookie = 0; + area_info info_area; + while(get_next_area_info(id, &cookie, &info_area) == B_OK) + accum.add(info_area, 2); + + if(accum.polling_goal_achieved()) + break; + } + } + +} diff --git a/src/lib/entropy/beos_stats/es_beos.h b/src/lib/entropy/beos_stats/es_beos.h new file mode 100644 index 000000000..5ccb430a5 --- /dev/null +++ b/src/lib/entropy/beos_stats/es_beos.h @@ -0,0 +1,28 @@ +/* +* BeOS EntropySource +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_BEOS_H__ +#define BOTAN_ENTROPY_SRC_BEOS_H__ + +#include + +namespace Botan { + +/** +* BeOS Entropy Source +*/ +class BeOS_EntropySource : public EntropySource + { + private: + std::string name() const { return "BeOS Statistics"; } + + void poll(Entropy_Accumulator& accum); + }; + +} + +#endif diff --git a/src/lib/entropy/beos_stats/info.txt b/src/lib/entropy/beos_stats/info.txt new file mode 100644 index 000000000..9ae527f49 --- /dev/null +++ b/src/lib/entropy/beos_stats/info.txt @@ -0,0 +1,17 @@ +define ENTROPY_SRC_BEOS 20131128 + + +es_beos.cpp + + + +es_beos.h + + + +haiku + + + +haiku -> root,be + diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.cpp b/src/lib/entropy/cryptoapi_rng/es_capi.cpp new file mode 100644 index 000000000..a706b4d5c --- /dev/null +++ b/src/lib/entropy/cryptoapi_rng/es_capi.cpp @@ -0,0 +1,93 @@ +/* +* Win32 CryptoAPI EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class CSP_Handle + { + public: + CSP_Handle(u64bit capi_provider) + { + valid = false; + DWORD prov_type = (DWORD)capi_provider; + + if(CryptAcquireContext(&handle, 0, 0, + prov_type, CRYPT_VERIFYCONTEXT)) + valid = true; + } + + ~CSP_Handle() + { + if(is_valid()) + CryptReleaseContext(handle, 0); + } + + size_t gen_random(byte out[], size_t n) const + { + if(is_valid() && CryptGenRandom(handle, static_cast(n), out)) + return n; + return 0; + } + + bool is_valid() const { return valid; } + + HCRYPTPROV get_handle() const { return handle; } + private: + HCRYPTPROV handle; + bool valid; + }; + +} + +/* +* Gather Entropy from Win32 CAPI +*/ +void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum) + { + secure_vector& io_buffer = accum.get_io_buffer(32); + + for(size_t i = 0; i != prov_types.size(); ++i) + { + CSP_Handle csp(prov_types[i]); + + size_t got = csp.gen_random(&io_buffer[0], io_buffer.size()); + + if(got) + { + accum.add(&io_buffer[0], io_buffer.size(), 6); + break; + } + } + } + +/* +* Win32_Capi_Entropysource Constructor +*/ +Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs) + { + std::vector capi_provs = split_on(provs, ':'); + + for(size_t i = 0; i != capi_provs.size(); ++i) + { + if(capi_provs[i] == "RSA_FULL") prov_types.push_back(PROV_RSA_FULL); + if(capi_provs[i] == "INTEL_SEC") prov_types.push_back(PROV_INTEL_SEC); + if(capi_provs[i] == "FORTEZZA") prov_types.push_back(PROV_FORTEZZA); + if(capi_provs[i] == "RNG") prov_types.push_back(PROV_RNG); + } + + if(prov_types.size() == 0) + prov_types.push_back(PROV_RSA_FULL); + } + +} diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.h b/src/lib/entropy/cryptoapi_rng/es_capi.h new file mode 100644 index 000000000..d75101923 --- /dev/null +++ b/src/lib/entropy/cryptoapi_rng/es_capi.h @@ -0,0 +1,37 @@ +/* +* Win32 CAPI EntropySource +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_WIN32_CAPI_H__ +#define BOTAN_ENTROPY_SRC_WIN32_CAPI_H__ + +#include +#include + +namespace Botan { + +/** +* Win32 CAPI Entropy Source +*/ +class Win32_CAPI_EntropySource : public EntropySource + { + public: + std::string name() const { return "Win32 CryptoGenRandom"; } + + void poll(Entropy_Accumulator& accum); + + /** + * Win32_Capi_Entropysource Constructor + * @param provs list of providers, separated by ':' + */ + Win32_CAPI_EntropySource(const std::string& provs = ""); + private: + std::vector prov_types; + }; + +} + +#endif diff --git a/src/lib/entropy/cryptoapi_rng/info.txt b/src/lib/entropy/cryptoapi_rng/info.txt new file mode 100644 index 000000000..d4ee13aea --- /dev/null +++ b/src/lib/entropy/cryptoapi_rng/info.txt @@ -0,0 +1,20 @@ +define ENTROPY_SRC_CAPI 20131128 + + +es_capi.cpp + + + +es_capi.h + + +# We'll just assume CAPI is there; this is OK except for 3.x, early +# versions of 95, and maybe NT 3.5 + +windows +cygwin + + + +windows -> advapi32.lib + diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp new file mode 100644 index 000000000..3f8df8749 --- /dev/null +++ b/src/lib/entropy/dev_random/dev_random.cpp @@ -0,0 +1,97 @@ +/* +* Reader of /dev/random and company +* (C) 1999-2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +Device_EntropySource constructor +Open a file descriptor to each (available) device in fsnames +*/ +Device_EntropySource::Device_EntropySource(const std::vector& fsnames) + { +#ifndef O_NONBLOCK + #define O_NONBLOCK 0 +#endif + +#ifndef O_NOCTTY + #define O_NOCTTY 0 +#endif + + const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; + + for(auto fsname : fsnames) + { + fd_type fd = ::open(fsname.c_str(), flags); + + if(fd >= 0 && fd < FD_SETSIZE) + m_devices.push_back(fd); + else if(fd >= 0) + ::close(fd); + } + } + +/** +Device_EntropySource destructor: close all open devices +*/ +Device_EntropySource::~Device_EntropySource() + { + for(size_t i = 0; i != m_devices.size(); ++i) + ::close(m_devices[i]); + } + +/** +* Gather entropy from a RNG device +*/ +void Device_EntropySource::poll(Entropy_Accumulator& accum) + { + if(m_devices.empty()) + return; + + const size_t ENTROPY_BITS_PER_BYTE = 8; + const size_t MS_WAIT_TIME = 32; + const size_t READ_ATTEMPT = std::max(accum.desired_remaining_bits() / 8, 16); + + int max_fd = m_devices[0]; + fd_set read_set; + FD_ZERO(&read_set); + for(size_t i = 0; i != m_devices.size(); ++i) + { + FD_SET(m_devices[i], &read_set); + max_fd = std::max(m_devices[i], max_fd); + } + + struct ::timeval timeout; + + timeout.tv_sec = (MS_WAIT_TIME / 1000); + timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000; + + if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0) + return; + + secure_vector& io_buffer = accum.get_io_buffer(READ_ATTEMPT); + + for(size_t i = 0; i != m_devices.size(); ++i) + { + if(FD_ISSET(m_devices[i], &read_set)) + { + const ssize_t got = ::read(m_devices[i], &io_buffer[0], io_buffer.size()); + accum.add(&io_buffer[0], got, ENTROPY_BITS_PER_BYTE); + } + } + } + +} diff --git a/src/lib/entropy/dev_random/dev_random.h b/src/lib/entropy/dev_random/dev_random.h new file mode 100644 index 000000000..d74412b27 --- /dev/null +++ b/src/lib/entropy/dev_random/dev_random.h @@ -0,0 +1,37 @@ +/* +* /dev/random EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_DEVICE_H__ +#define BOTAN_ENTROPY_SRC_DEVICE_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Entropy source reading from kernel devices like /dev/random +*/ +class Device_EntropySource : public EntropySource + { + public: + std::string name() const { return "RNG Device Reader"; } + + void poll(Entropy_Accumulator& accum); + + Device_EntropySource(const std::vector& fsnames); + ~Device_EntropySource(); + private: + typedef int fd_type; + + std::vector m_devices; + }; + +} + +#endif diff --git a/src/lib/entropy/dev_random/info.txt b/src/lib/entropy/dev_random/info.txt new file mode 100644 index 000000000..98a6a7e61 --- /dev/null +++ b/src/lib/entropy/dev_random/info.txt @@ -0,0 +1,27 @@ +define ENTROPY_SRC_DEV_RANDOM 20131128 + + +dev_random.cpp + + + +dev_random.h + + + +aix +cygwin +darwin +dragonfly +freebsd +haiku +hpux +hurd +irix +linux +netbsd +openbsd +qnx +solaris +tru64 + diff --git a/src/lib/entropy/egd/es_egd.cpp b/src/lib/entropy/egd/es_egd.cpp new file mode 100644 index 000000000..d8dbecd44 --- /dev/null +++ b/src/lib/entropy/egd/es_egd.cpp @@ -0,0 +1,156 @@ +/* +* EGD EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifndef PF_LOCAL + #define PF_LOCAL PF_UNIX +#endif + +namespace Botan { + +EGD_EntropySource::EGD_Socket::EGD_Socket(const std::string& path) : + socket_path(path), m_fd(-1) + { + } + +/** +* Attempt a connection to an EGD/PRNGD socket +*/ +int EGD_EntropySource::EGD_Socket::open_socket(const std::string& path) + { + int fd = ::socket(PF_LOCAL, SOCK_STREAM, 0); + + if(fd >= 0) + { + sockaddr_un addr; + std::memset(&addr, 0, sizeof(addr)); + addr.sun_family = PF_LOCAL; + + if(sizeof(addr.sun_path) < path.length() + 1) + throw std::invalid_argument("EGD socket path is too long"); + + std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path)); + + int len = sizeof(addr.sun_family) + std::strlen(addr.sun_path) + 1; + + if(::connect(fd, reinterpret_cast(&addr), len) < 0) + { + ::close(fd); + fd = -1; + } + } + + return fd; + } + +/** +* Attempt to read entropy from EGD +*/ +size_t EGD_EntropySource::EGD_Socket::read(byte outbuf[], size_t length) + { + if(length == 0) + return 0; + + if(m_fd < 0) + { + m_fd = open_socket(socket_path); + if(m_fd < 0) + return 0; + } + + try + { + // 1 == EGD command for non-blocking read + byte egd_read_command[2] = { + 1, static_cast(std::min(length, 255)) }; + + if(::write(m_fd, egd_read_command, 2) != 2) + throw std::runtime_error("Writing entropy read command to EGD failed"); + + byte out_len = 0; + if(::read(m_fd, &out_len, 1) != 1) + throw std::runtime_error("Reading response length from EGD failed"); + + if(out_len > egd_read_command[1]) + throw std::runtime_error("Bogus length field received from EGD"); + + ssize_t count = ::read(m_fd, outbuf, out_len); + + if(count != out_len) + throw std::runtime_error("Reading entropy result from EGD failed"); + + return static_cast(count); + } + catch(std::exception) + { + this->close(); + // Will attempt to reopen next poll + } + + return 0; + } + +void EGD_EntropySource::EGD_Socket::close() + { + if(m_fd > 0) + { + ::close(m_fd); + m_fd = -1; + } + } + +/** +* EGD_EntropySource constructor +*/ +EGD_EntropySource::EGD_EntropySource(const std::vector& paths) + { + for(size_t i = 0; i != paths.size(); ++i) + sockets.push_back(EGD_Socket(paths[i])); + } + +EGD_EntropySource::~EGD_EntropySource() + { + for(size_t i = 0; i != sockets.size(); ++i) + sockets[i].close(); + sockets.clear(); + } + +/** +* Gather Entropy from EGD +*/ +void EGD_EntropySource::poll(Entropy_Accumulator& accum) + { + size_t go_get = std::min(accum.desired_remaining_bits() / 8, 32); + + secure_vector& io_buffer = accum.get_io_buffer(go_get); + + for(size_t i = 0; i != sockets.size(); ++i) + { + size_t got = sockets[i].read(&io_buffer[0], io_buffer.size()); + + if(got) + { + accum.add(&io_buffer[0], got, 6); + break; + } + } + } + +} diff --git a/src/lib/entropy/egd/es_egd.h b/src/lib/entropy/egd/es_egd.h new file mode 100644 index 000000000..02c52b9a3 --- /dev/null +++ b/src/lib/entropy/egd/es_egd.h @@ -0,0 +1,49 @@ +/* +* EGD EntropySource +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_EGD_H__ +#define BOTAN_ENTROPY_SRC_EGD_H__ + +#include +#include +#include + +namespace Botan { + +/** +* EGD Entropy Source +*/ +class EGD_EntropySource : public EntropySource + { + public: + std::string name() const { return "EGD/PRNGD"; } + + void poll(Entropy_Accumulator& accum); + + EGD_EntropySource(const std::vector&); + ~EGD_EntropySource(); + private: + class EGD_Socket + { + public: + EGD_Socket(const std::string& path); + + void close(); + size_t read(byte outbuf[], size_t length); + private: + static int open_socket(const std::string& path); + + std::string socket_path; + int m_fd; // cached fd + }; + + std::vector sockets; + }; + +} + +#endif diff --git a/src/lib/entropy/egd/info.txt b/src/lib/entropy/egd/info.txt new file mode 100644 index 000000000..b93c4526d --- /dev/null +++ b/src/lib/entropy/egd/info.txt @@ -0,0 +1,30 @@ +define ENTROPY_SRC_EGD 20131128 + + +es_egd.cpp + + + +es_egd.h + + + +solaris -> socket +qnx -> socket + + + +aix +cygwin +darwin +freebsd +dragonfly +hpux +irix +linux +netbsd +openbsd +qnx +solaris +tru64 + diff --git a/src/lib/entropy/entropy_src.h b/src/lib/entropy/entropy_src.h new file mode 100644 index 000000000..552eca9de --- /dev/null +++ b/src/lib/entropy/entropy_src.h @@ -0,0 +1,141 @@ +/* +* EntropySource +* (C) 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SOURCE_BASE_H__ +#define BOTAN_ENTROPY_SOURCE_BASE_H__ + +#include +#include + +namespace Botan { + +/** +* Class used to accumulate the poll results of EntropySources +*/ +class BOTAN_DLL Entropy_Accumulator + { + public: + /** + * Initialize an Entropy_Accumulator + * @param goal is how many bits we would like to collect + */ + Entropy_Accumulator(size_t goal) : + entropy_goal(goal), collected_bits(0) {} + + virtual ~Entropy_Accumulator() {} + + /** + * Get a cached I/O buffer (purely for minimizing allocation + * overhead to polls) + * + * @param size requested size for the I/O buffer + * @return cached I/O buffer for repeated polls + */ + secure_vector& get_io_buffer(size_t size) + { io_buffer.resize(size); return io_buffer; } + + /** + * @return number of bits collected so far + */ + size_t bits_collected() const + { return static_cast(collected_bits); } + + /** + * @return if our polling goal has been achieved + */ + bool polling_goal_achieved() const + { return (collected_bits >= entropy_goal); } + + /** + * @return how many bits we need to reach our polling goal + */ + size_t desired_remaining_bits() const + { + if(collected_bits >= entropy_goal) + return 0; + return static_cast(entropy_goal - collected_bits); + } + + /** + * Add entropy to the accumulator + * @param bytes the input bytes + * @param length specifies how many bytes the input is + * @param entropy_bits_per_byte is a best guess at how much + * entropy per byte is in this input + */ + void add(const void* bytes, size_t length, double entropy_bits_per_byte) + { + add_bytes(reinterpret_cast(bytes), length); + collected_bits += entropy_bits_per_byte * length; + } + + /** + * Add entropy to the accumulator + * @param v is some value + * @param entropy_bits_per_byte is a best guess at how much + * entropy per byte is in this input + */ + template + void add(const T& v, double entropy_bits_per_byte) + { + add(&v, sizeof(T), entropy_bits_per_byte); + } + private: + virtual void add_bytes(const byte bytes[], size_t length) = 0; + + secure_vector io_buffer; + size_t entropy_goal; + double collected_bits; + }; + +/** +* Entropy accumulator that puts the input into a Buffered_Computation +*/ +class BOTAN_DLL Entropy_Accumulator_BufferedComputation : + public Entropy_Accumulator + { + public: + /** + * @param sink the hash or MAC we are feeding the poll data into + * @param goal is how many bits we want to collect in this poll + */ + Entropy_Accumulator_BufferedComputation(Buffered_Computation& sink, + size_t goal) : + Entropy_Accumulator(goal), entropy_sink(sink) {} + + private: + void add_bytes(const byte bytes[], size_t length) override + { + entropy_sink.update(bytes, length); + } + + Buffered_Computation& entropy_sink; + }; + +/** +* Abstract interface to a source of entropy +*/ +class BOTAN_DLL EntropySource + { + public: + /** + * @return name identifying this entropy source + */ + virtual std::string name() const = 0; + + /** + * Perform an entropy gathering poll + * @param accum is an accumulator object that will be given entropy + */ + virtual void poll(Entropy_Accumulator& accum) = 0; + + virtual ~EntropySource() {} + }; + +} + +#endif diff --git a/src/lib/entropy/hres_timer/hres_timer.cpp b/src/lib/entropy/hres_timer/hres_timer.cpp new file mode 100644 index 000000000..7295a119b --- /dev/null +++ b/src/lib/entropy/hres_timer/hres_timer.cpp @@ -0,0 +1,117 @@ +/* +* High Resolution Timestamp Entropy Source +* (C) 1999-2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER) + #include +#endif + +namespace Botan { + +/* +* Get the timestamp +*/ +void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum) + { + // Don't count the timestamp as contributing any entropy + const double ESTIMATED_ENTROPY_PER_BYTE = 0.0; + +#if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER) + { + LARGE_INTEGER tv; + ::QueryPerformanceCounter(&tv); + accum.add(tv.QuadPart, ESTIMATED_ENTROPY_PER_BYTE); + } +#endif + +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + +#define CLOCK_POLL(src) \ + do { \ + struct timespec ts; \ + ::clock_gettime(src, &ts); \ + accum.add(&ts, sizeof(ts), ESTIMATED_ENTROPY_PER_BYTE); \ + } while(0) + +#if defined(CLOCK_REALTIME) + CLOCK_POLL(CLOCK_REALTIME); +#endif + +#if defined(CLOCK_REALTIME_COARSE) + CLOCK_POLL(CLOCK_REALTIME_COARSE); +#endif + +#if defined(CLOCK_MONOTONIC) + CLOCK_POLL(CLOCK_MONOTONIC); +#endif + +#if defined(CLOCK_MONOTONIC_COARSE) + CLOCK_POLL(CLOCK_MONOTONIC_COARSE); +#endif + +#if defined(CLOCK_MONOTONIC_RAW) + CLOCK_POLL(CLOCK_MONOTONIC_RAW); +#endif + +#if defined(CLOCK_BOOTTIME) + CLOCK_POLL(CLOCK_BOOTTIME); +#endif + +#if defined(CLOCK_PROCESS_CPUTIME_ID) + CLOCK_POLL(CLOCK_PROCESS_CPUTIME_ID); +#endif + +#if defined(CLOCK_THREAD_CPUTIME_ID) + CLOCK_POLL(CLOCK_THREAD_CPUTIME_ID); +#endif + +#undef CLOCK_POLL + +#endif + +#if BOTAN_USE_GCC_INLINE_ASM + + u64bit rtc = 0; + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + if(CPUID::has_rdtsc()) // not availble on all x86 CPUs + { + u32bit rtc_low = 0, rtc_high = 0; + asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); + rtc = (static_cast(rtc_high) << 32) | rtc_low; + } + +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + u32bit rtc_low = 0, rtc_high = 0; + asm volatile("mftbu %0; mftb %1" : "=r" (rtc_high), "=r" (rtc_low)); + rtc = (static_cast(rtc_high) << 32) | rtc_low; + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + asm volatile("rpcc %0" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) + asm volatile("rd %%tick, %0" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + asm volatile("mov %0=ar.itc" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_S390X) + asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc"); + +#elif defined(BOTAN_TARGET_ARCH_IS_HPPA) + asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only? + +#endif + + accum.add(rtc, ESTIMATED_ENTROPY_PER_BYTE); + +#endif + } + +} diff --git a/src/lib/entropy/hres_timer/hres_timer.h b/src/lib/entropy/hres_timer/hres_timer.h new file mode 100644 index 000000000..8b95c8308 --- /dev/null +++ b/src/lib/entropy/hres_timer/hres_timer.h @@ -0,0 +1,30 @@ +/* +* High Resolution Timestamp Entropy Source +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_HRES_TIMER_H__ +#define BOTAN_ENTROPY_SRC_HRES_TIMER_H__ + +#include + +namespace Botan { + +/** +* Entropy source using high resolution timers +* +* @note Any results from timers are marked as not contributing entropy +* to the poll, as a local attacker could observe them directly. +*/ +class High_Resolution_Timestamp : public EntropySource + { + public: + std::string name() const { return "High Resolution Timestamp"; } + void poll(Entropy_Accumulator& accum); + }; + +} + +#endif diff --git a/src/lib/entropy/hres_timer/info.txt b/src/lib/entropy/hres_timer/info.txt new file mode 100644 index 000000000..dfe8fab0b --- /dev/null +++ b/src/lib/entropy/hres_timer/info.txt @@ -0,0 +1,13 @@ +define ENTROPY_SRC_HIGH_RESOLUTION_TIMER 20131128 + + +hres_timer.cpp + + + +hres_timer.h + + + +linux -> rt + diff --git a/src/lib/entropy/info.txt b/src/lib/entropy/info.txt new file mode 100644 index 000000000..d991577f7 --- /dev/null +++ b/src/lib/entropy/info.txt @@ -0,0 +1,3 @@ + +algo_base + diff --git a/src/lib/entropy/proc_walk/info.txt b/src/lib/entropy/proc_walk/info.txt new file mode 100644 index 000000000..2a53a7ed8 --- /dev/null +++ b/src/lib/entropy/proc_walk/info.txt @@ -0,0 +1,30 @@ +define ENTROPY_SRC_PROC_WALKER 20131128 + + +proc_walk.cpp + + + +proc_walk.h + + + +aix +cygwin +darwin +dragonfly +freebsd +hpux +hurd +irix +linux +netbsd +openbsd +qnx +solaris +tru64 + + + +alloc + diff --git a/src/lib/entropy/proc_walk/proc_walk.cpp b/src/lib/entropy/proc_walk/proc_walk.cpp new file mode 100644 index 000000000..050d9dcf7 --- /dev/null +++ b/src/lib/entropy/proc_walk/proc_walk.cpp @@ -0,0 +1,173 @@ +/* +* Entropy source based on reading files in /proc on the assumption +* that a remote attacker will have difficulty guessing some of them. +* +* (C) 1999-2008,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +#ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309 +#endif + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Returns file descriptors. Until it doesn't +*/ +class File_Descriptor_Source + { + public: + /** + * @return next file descriptor, or -1 if done + */ + virtual int next_fd() = 0; + + virtual ~File_Descriptor_Source() {} + }; + +namespace { + +class Directory_Walker : public File_Descriptor_Source + { + public: + Directory_Walker(const std::string& root) : + m_cur_dir(std::make_pair(nullptr, "")) + { + if(DIR* root_dir = ::opendir(root.c_str())) + m_cur_dir = std::make_pair(root_dir, root); + } + + ~Directory_Walker() + { + if(m_cur_dir.first) + ::closedir(m_cur_dir.first); + } + + int next_fd(); + private: + void add_directory(const std::string& dirname) + { + m_dirlist.push_back(dirname); + } + + std::pair get_next_dirent(); + + std::pair m_cur_dir; + std::deque m_dirlist; + }; + +std::pair Directory_Walker::get_next_dirent() + { + while(m_cur_dir.first) + { + if(struct dirent* dir = ::readdir(m_cur_dir.first)) + return std::make_pair(dir, m_cur_dir.second); + + ::closedir(m_cur_dir.first); + m_cur_dir = std::make_pair(nullptr, ""); + + while(!m_dirlist.empty() && !m_cur_dir.first) + { + const std::string next_dir_name = m_dirlist[0]; + m_dirlist.pop_front(); + + if(DIR* next_dir = ::opendir(next_dir_name.c_str())) + m_cur_dir = std::make_pair(next_dir, next_dir_name); + } + } + + return std::make_pair(nullptr, ""); // nothing left + } + +int Directory_Walker::next_fd() + { + while(true) + { + std::pair entry = get_next_dirent(); + + if(!entry.first) + break; // no more dirs + + const std::string filename = entry.first->d_name; + + if(filename == "." || filename == "..") + continue; + + const std::string full_path = entry.second + '/' + filename; + + struct stat stat_buf; + if(::lstat(full_path.c_str(), &stat_buf) == -1) + continue; + + if(S_ISDIR(stat_buf.st_mode)) + { + add_directory(full_path); + } + else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH)) + { + int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY); + + if(fd > 0) + return fd; + } + } + + return -1; + } + +} + +/** +* ProcWalking_EntropySource Destructor +*/ +ProcWalking_EntropySource::~ProcWalking_EntropySource() + { + // for ~unique_ptr + } + +void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum) + { + const size_t MAX_FILES_READ_PER_POLL = 2048; + + if(!m_dir) + m_dir = new Directory_Walker(m_path); + + secure_vector& io_buffer = accum.get_io_buffer(4096); + + for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i) + { + int fd = m_dir->next_fd(); + + // If we've exhaused this walk of the directory, halt the poll + if(fd == -1) + { + delete m_dir; + m_dir = nullptr; + break; + } + + ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size()); + ::close(fd); + + if(got > 0) + accum.add(&io_buffer[0], got, .001); + + if(accum.polling_goal_achieved()) + break; + } + } + +} diff --git a/src/lib/entropy/proc_walk/proc_walk.h b/src/lib/entropy/proc_walk/proc_walk.h new file mode 100644 index 000000000..04c3b1bba --- /dev/null +++ b/src/lib/entropy/proc_walk/proc_walk.h @@ -0,0 +1,37 @@ +/* +* File Tree Walking EntropySource +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_PROC_WALK_H__ +#define BOTAN_ENTROPY_SRC_PROC_WALK_H__ + +#include +#include + +namespace Botan { + +/** +* File Tree Walking Entropy Source +*/ +class ProcWalking_EntropySource : public EntropySource + { + public: + std::string name() const { return "Proc Walker"; } + + void poll(Entropy_Accumulator& accum); + + ProcWalking_EntropySource(const std::string& root_dir) : + m_path(root_dir), m_dir(nullptr) {} + + ~ProcWalking_EntropySource(); + private: + const std::string m_path; + class File_Descriptor_Source* m_dir; + }; + +} + +#endif diff --git a/src/lib/entropy/rdrand/info.txt b/src/lib/entropy/rdrand/info.txt new file mode 100644 index 000000000..546ab699a --- /dev/null +++ b/src/lib/entropy/rdrand/info.txt @@ -0,0 +1,22 @@ +define ENTROPY_SRC_RDRAND 20131128 + +need_isa rdrand + + +rdrand.cpp + + + +rdrand.h + + + +x86_32 +x86_64 + + + +gcc +clang +icc + diff --git a/src/lib/entropy/rdrand/rdrand.cpp b/src/lib/entropy/rdrand/rdrand.cpp new file mode 100644 index 000000000..0dae697c8 --- /dev/null +++ b/src/lib/entropy/rdrand/rdrand.cpp @@ -0,0 +1,60 @@ +/* +* Entropy Source Using Intel's rdrand instruction +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if !defined(BOTAN_USE_GCC_INLINE_ASM) + #include +#endif + +namespace Botan { + +/* +* Get the timestamp +*/ +void Intel_Rdrand::poll(Entropy_Accumulator& accum) + { + if(!CPUID::has_rdrand()) + return; + + /* + * Put an upper bound on the total entropy we're willing to claim + * for any one polling of rdrand to prevent it from swamping our + * poll. Internally, the rdrand system is a DRGB that reseeds at a + * somewhat unpredictable rate (the current conditions are + * documented, but that might not be true for different + * implementations, eg on Haswell or a future AMD chip, so I don't + * want to assume). This limit ensures we're going to poll at least + * one other source so we have some diversity in our inputs. + */ + + const size_t POLL_UPPER_BOUND = 96; + const size_t RDRAND_POLLS = 32; + const double ENTROPY_PER_POLL = + static_cast(POLL_UPPER_BOUND) / (RDRAND_POLLS * 4); + + for(size_t i = 0; i != RDRAND_POLLS; ++i) + { + unsigned int r = 0; + +#if BOTAN_USE_GCC_INLINE_ASM + int cf = 0; + + // Encoding of rdrand %eax + asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" : + "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); +#else + int cf = _rdrand32_step(&r); +#endif + + if(cf == 1) + accum.add(r, ENTROPY_PER_POLL); + } + } + +} diff --git a/src/lib/entropy/rdrand/rdrand.h b/src/lib/entropy/rdrand/rdrand.h new file mode 100644 index 000000000..d7629d37f --- /dev/null +++ b/src/lib/entropy/rdrand/rdrand.h @@ -0,0 +1,28 @@ +/* +* Entropy Source Using Intel's rdrand instruction +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_RDRAND_H__ +#define BOTAN_ENTROPY_SRC_RDRAND_H__ + +#include + +namespace Botan { + +/** +* Entropy source using the rdrand instruction first introduced on +* Intel's Ivy Bridge architecture. +*/ +class Intel_Rdrand : public EntropySource + { + public: + std::string name() const { return "Intel Rdrand"; } + void poll(Entropy_Accumulator& accum); + }; + +} + +#endif diff --git a/src/lib/entropy/unix_procs/info.txt b/src/lib/entropy/unix_procs/info.txt new file mode 100644 index 000000000..755d2565d --- /dev/null +++ b/src/lib/entropy/unix_procs/info.txt @@ -0,0 +1,25 @@ +define ENTROPY_SRC_UNIX_PROCESS_RUNNER 20131128 + + +unix_procs.cpp +unix_proc_sources.cpp + + + +unix_procs.h + + + +aix +cygwin +darwin +freebsd +haiku +hpux +irix +linux +netbsd +qnx +solaris +tru64 + diff --git a/src/lib/entropy/unix_procs/unix_proc_sources.cpp b/src/lib/entropy/unix_procs/unix_proc_sources.cpp new file mode 100644 index 000000000..6cf185064 --- /dev/null +++ b/src/lib/entropy/unix_procs/unix_proc_sources.cpp @@ -0,0 +1,65 @@ +/* +* Program List for Unix_EntropySource +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/** +* Default Commands for Entropy Gathering +*/ +std::vector> Unix_EntropySource::get_default_sources() + { + std::vector> srcs; + + srcs.push_back({ "netstat", "-in" }); + srcs.push_back({ "pfstat" }); + srcs.push_back({ "vmstat", "-s" }); + srcs.push_back({ "vmstat" }); + + srcs.push_back({ "arp", "-a", "-n" }); + srcs.push_back({ "ifconfig", "-a" }); + srcs.push_back({ "iostat" }); + srcs.push_back({ "ipcs", "-a" }); + srcs.push_back({ "mpstat" }); + srcs.push_back({ "netstat", "-an" }); + srcs.push_back({ "netstat", "-s" }); + srcs.push_back({ "nfsstat" }); + srcs.push_back({ "portstat" }); + srcs.push_back({ "procinfo", "-a" }); + srcs.push_back({ "pstat", "-T" }); + srcs.push_back({ "pstat", "-s" }); + srcs.push_back({ "uname", "-a" }); + srcs.push_back({ "uptime" }); + + srcs.push_back({ "listarea" }); + srcs.push_back({ "listdev" }); + srcs.push_back({ "ps", "-A" }); + srcs.push_back({ "sysinfo" }); + + srcs.push_back({ "finger" }); + srcs.push_back({ "mailstats" }); + srcs.push_back({ "rpcinfo", "-p", "localhost" }); + srcs.push_back({ "who" }); + + srcs.push_back({ "df", "-l" }); + srcs.push_back({ "dmesg" }); + srcs.push_back({ "last", "-5" }); + srcs.push_back({ "ls", "-alni", "/proc" }); + srcs.push_back({ "ls", "-alni", "/tmp" }); + srcs.push_back({ "pstat", "-f" }); + + srcs.push_back({ "ps", "-elf" }); + srcs.push_back({ "ps", "aux" }); + + srcs.push_back({ "lsof", "-n" }); + srcs.push_back({ "sar", "-A" }); + + return srcs; + } + +} diff --git a/src/lib/entropy/unix_procs/unix_procs.cpp b/src/lib/entropy/unix_procs/unix_procs.cpp new file mode 100644 index 000000000..c36941f43 --- /dev/null +++ b/src/lib/entropy/unix_procs/unix_procs.cpp @@ -0,0 +1,258 @@ + /* +* Gather entropy by running various system commands in the hopes that +* some of the output cannot be guessed by a remote attacker. +* +* (C) 1999-2009,2013 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string find_full_path_if_exists(const std::vector& trusted_path, + const std::string& proc) + { + for(auto dir : trusted_path) + { + const std::string full_path = dir + "/" + proc; + if(::access(full_path.c_str(), X_OK) == 0) + return full_path; + } + + return ""; + } + +size_t concurrent_processes(size_t user_request) + { + const size_t DEFAULT_CONCURRENT = 2; + const size_t MAX_CONCURRENT = 8; + + if(user_request > 0 && user_request < MAX_CONCURRENT) + return user_request; + + const long online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN); + + if(online_cpus > 0) + return static_cast(online_cpus); // maybe fewer? + + return DEFAULT_CONCURRENT; + } + +} + +/** +* Unix_EntropySource Constructor +*/ +Unix_EntropySource::Unix_EntropySource(const std::vector& trusted_path, + size_t proc_cnt) : + m_trusted_paths(trusted_path), + m_concurrent(concurrent_processes(proc_cnt)) + { + } + +void UnixProcessInfo_EntropySource::poll(Entropy_Accumulator& accum) + { + accum.add(::getpid(), 0.0); + accum.add(::getppid(), 0.0); + accum.add(::getuid(), 0.0); + accum.add(::getgid(), 0.0); + accum.add(::getsid(0), 0.0); + accum.add(::getpgrp(), 0.0); + + struct ::rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + accum.add(usage, 0.0); + + ::getrusage(RUSAGE_CHILDREN, &usage); + accum.add(usage, 0.0); + } + +namespace { + +void do_exec(const std::vector& args) + { + // cleaner way to do this? + const char* arg0 = (args.size() > 0) ? args[0].c_str() : nullptr; + const char* arg1 = (args.size() > 1) ? args[1].c_str() : nullptr; + const char* arg2 = (args.size() > 2) ? args[2].c_str() : nullptr; + const char* arg3 = (args.size() > 3) ? args[3].c_str() : nullptr; + const char* arg4 = (args.size() > 4) ? args[4].c_str() : nullptr; + + ::execl(arg0, arg0, arg1, arg2, arg3, arg4, NULL); + } + +} + +void Unix_EntropySource::Unix_Process::spawn(const std::vector& args) + { + shutdown(); + + int pipe[2]; + if(::pipe(pipe) != 0) + return; + + pid_t pid = ::fork(); + + if(pid == -1) + { + ::close(pipe[0]); + ::close(pipe[1]); + } + else if(pid > 0) // in parent + { + m_pid = pid; + m_fd = pipe[0]; + ::close(pipe[1]); + } + else // in child + { + if(::dup2(pipe[1], STDOUT_FILENO) == -1) + ::exit(127); + if(::close(pipe[0]) != 0 || ::close(pipe[1]) != 0) + ::exit(127); + if(close(STDERR_FILENO) != 0) + ::exit(127); + + do_exec(args); + ::exit(127); + } + } + +void Unix_EntropySource::Unix_Process::shutdown() + { + if(m_pid == -1) + return; + + ::close(m_fd); + m_fd = -1; + + pid_t reaped = waitpid(m_pid, nullptr, WNOHANG); + + if(reaped == 0) + { + /* + * Child is still alive - send it SIGTERM, sleep for a bit and + * try to reap again, if still alive send SIGKILL + */ + kill(m_pid, SIGTERM); + + struct ::timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1000; + select(0, nullptr, nullptr, nullptr, &tv); + + reaped = ::waitpid(m_pid, nullptr, WNOHANG); + + if(reaped == 0) + { + ::kill(m_pid, SIGKILL); + do + reaped = ::waitpid(m_pid, nullptr, 0); + while(reaped == -1); + } + } + + m_pid = -1; + } + +const std::vector& Unix_EntropySource::next_source() + { + const auto& src = m_sources.at(m_sources_idx); + m_sources_idx = (m_sources_idx + 1) % m_sources.size(); + return src; + } + +void Unix_EntropySource::poll(Entropy_Accumulator& accum) + { + // refuse to run as root (maybe instead setuid to nobody before exec?) + // fixme: this should also check for setgid + if(::getuid() == 0 || ::geteuid() == 0) + return; + + if(m_sources.empty()) + { + auto sources = get_default_sources(); + + for(auto src : sources) + { + const std::string path = find_full_path_if_exists(m_trusted_paths, src[0]); + if(path != "") + { + src[0] = path; + m_sources.push_back(src); + } + } + } + + if(m_sources.empty()) + return; // still empty, really nothing to try + + const size_t MS_WAIT_TIME = 32; + const double ENTROPY_ESTIMATE = 1.0 / 1024; + + secure_vector& io_buffer = accum.get_io_buffer(4*1024); // page + + while(!accum.polling_goal_achieved()) + { + while(m_procs.size() < m_concurrent) + m_procs.emplace_back(Unix_Process(next_source())); + + fd_set read_set; + FD_ZERO(&read_set); + + std::vector fds; + + for(auto& proc : m_procs) + { + int fd = proc.fd(); + if(fd > 0) + { + fds.push_back(fd); + FD_SET(fd, &read_set); + } + } + + if(fds.empty()) + break; + + const int max_fd = *std::max_element(fds.begin(), fds.end()); + + struct ::timeval timeout; + timeout.tv_sec = (MS_WAIT_TIME / 1000); + timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000; + + if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0) + return; // or continue? + + for(auto& proc : m_procs) + { + int fd = proc.fd(); + + if(FD_ISSET(fd, &read_set)) + { + const ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size()); + if(got > 0) + accum.add(&io_buffer[0], got, ENTROPY_ESTIMATE); + else + proc.spawn(next_source()); + } + } + } + } + +} diff --git a/src/lib/entropy/unix_procs/unix_procs.h b/src/lib/entropy/unix_procs/unix_procs.h new file mode 100644 index 000000000..7c1ae8c65 --- /dev/null +++ b/src/lib/entropy/unix_procs/unix_procs.h @@ -0,0 +1,89 @@ +/* +* Unix EntropySource +* (C) 1999-2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_UNIX_H__ +#define BOTAN_ENTROPY_SRC_UNIX_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Entropy source for generic Unix. Runs various programs trying to +* gather data hard for a remote attacker to guess. Probably not too +* effective against local attackers as they can sample from the same +* distribution. +*/ +class Unix_EntropySource : public EntropySource + { + public: + std::string name() const { return "Unix Process Runner"; } + + void poll(Entropy_Accumulator& accum) override; + + /** + * @param trusted_paths is a list of directories that are assumed + * to contain only 'safe' binaries. If an attacker can write + * an executable to one of these directories then we will + * run arbitrary code. + */ + Unix_EntropySource(const std::vector& trusted_paths, + size_t concurrent_processes = 0); + private: + static std::vector> get_default_sources(); + + class Unix_Process + { + public: + int fd() const { return m_fd; } + + void spawn(const std::vector& args); + void shutdown(); + + Unix_Process() {} + + Unix_Process(const std::vector& args) { spawn(args); } + + ~Unix_Process() { shutdown(); } + + Unix_Process(Unix_Process&& other) + { + std::swap(m_fd, other.m_fd); + std::swap(m_pid, other.m_pid); + } + + Unix_Process(const Unix_Process&) = delete; + Unix_Process& operator=(const Unix_Process&) = delete; + private: + int m_fd = -1; + pid_t m_pid = -1; + }; + + const std::vector& next_source(); + + const std::vector m_trusted_paths; + const size_t m_concurrent; + + std::vector> m_sources; + size_t m_sources_idx = 0; + + std::vector m_procs; + }; + +class UnixProcessInfo_EntropySource : public EntropySource + { + public: + std::string name() const { return "Unix Process Info"; } + + void poll(Entropy_Accumulator& accum); + }; + +} + +#endif diff --git a/src/lib/entropy/win32_stats/es_win32.cpp b/src/lib/entropy/win32_stats/es_win32.cpp new file mode 100644 index 000000000..fff11592d --- /dev/null +++ b/src/lib/entropy/win32_stats/es_win32.cpp @@ -0,0 +1,118 @@ +/* +* Win32 EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/** +* Win32 poll using stats functions including Tooltip32 +*/ +void Win32_EntropySource::poll(Entropy_Accumulator& accum) + { + /* + First query a bunch of basic statistical stuff, though + don't count it for much in terms of contributed entropy. + */ + accum.add(GetTickCount(), 0); + accum.add(GetMessagePos(), 0); + accum.add(GetMessageTime(), 0); + accum.add(GetInputState(), 0); + accum.add(GetCurrentProcessId(), 0); + accum.add(GetCurrentThreadId(), 0); + + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + accum.add(sys_info, 1); + + MEMORYSTATUS mem_info; + GlobalMemoryStatus(&mem_info); + accum.add(mem_info, 1); + + POINT point; + GetCursorPos(&point); + accum.add(point, 1); + + GetCaretPos(&point); + accum.add(point, 1); + + LARGE_INTEGER perf_counter; + QueryPerformanceCounter(&perf_counter); + accum.add(perf_counter, 0); + + /* + Now use the Tooltip library to iterate throug various objects on + the system, including processes, threads, and heap objects. + */ + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + +#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \ + if(!accum.polling_goal_achieved()) \ + { \ + DATA_TYPE info; \ + info.dwSize = sizeof(DATA_TYPE); \ + if(FUNC_FIRST(snapshot, &info)) \ + { \ + do \ + { \ + accum.add(info, 1); \ + } while(FUNC_NEXT(snapshot, &info)); \ + } \ + } + + TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next); + TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next); + TOOLHELP32_ITER(THREADENTRY32, Thread32First, Thread32Next); + +#undef TOOLHELP32_ITER + + if(!accum.polling_goal_achieved()) + { + size_t heap_lists_found = 0; + HEAPLIST32 heap_list; + heap_list.dwSize = sizeof(HEAPLIST32); + + const size_t HEAP_LISTS_MAX = 32; + const size_t HEAP_OBJS_PER_LIST = 128; + + if(Heap32ListFirst(snapshot, &heap_list)) + { + do + { + accum.add(heap_list, 1); + + if(++heap_lists_found > HEAP_LISTS_MAX) + break; + + size_t heap_objs_found = 0; + HEAPENTRY32 heap_entry; + heap_entry.dwSize = sizeof(HEAPENTRY32); + if(Heap32First(&heap_entry, heap_list.th32ProcessID, + heap_list.th32HeapID)) + { + do + { + if(heap_objs_found++ > HEAP_OBJS_PER_LIST) + break; + accum.add(heap_entry, 1); + } while(Heap32Next(&heap_entry)); + } + + if(accum.polling_goal_achieved()) + break; + + } while(Heap32ListNext(snapshot, &heap_list)); + } + } + + CloseHandle(snapshot); + } + +} diff --git a/src/lib/entropy/win32_stats/es_win32.h b/src/lib/entropy/win32_stats/es_win32.h new file mode 100644 index 000000000..6c7c9ee09 --- /dev/null +++ b/src/lib/entropy/win32_stats/es_win32.h @@ -0,0 +1,27 @@ +/* +* Win32 EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENTROPY_SRC_WIN32_H__ +#define BOTAN_ENTROPY_SRC_WIN32_H__ + +#include + +namespace Botan { + +/** +* Win32 Entropy Source +*/ +class Win32_EntropySource : public EntropySource + { + public: + std::string name() const { return "Win32 Statistics"; } + void poll(Entropy_Accumulator& accum); + }; + +} + +#endif diff --git a/src/lib/entropy/win32_stats/info.txt b/src/lib/entropy/win32_stats/info.txt new file mode 100644 index 000000000..48eb91faa --- /dev/null +++ b/src/lib/entropy/win32_stats/info.txt @@ -0,0 +1,19 @@ +define ENTROPY_SRC_WIN32 20131128 + + +es_win32.cpp + + + +es_win32.h + + + +windows +cygwin +mingw + + + +windows -> user32.lib + diff --git a/src/lib/filters/aead_filt/aead_filt.h b/src/lib/filters/aead_filt/aead_filt.h new file mode 100644 index 000000000..65f73d7d3 --- /dev/null +++ b/src/lib/filters/aead_filt/aead_filt.h @@ -0,0 +1,40 @@ +/* +* Filter interface for AEAD Modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_FILTER_H__ +#define BOTAN_AEAD_FILTER_H__ + +#include +#include + +namespace Botan { + +/** +* Filter interface for AEAD Modes +*/ +class BOTAN_DLL AEAD_Filter : public Transformation_Filter + { + public: + AEAD_Filter(AEAD_Mode* aead) : Transformation_Filter(aead) {} + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key + * and before end_msg. + * + * @param ad the associated data + * @param ad_len length of add in bytes + */ + void set_associated_data(const byte ad[], size_t ad_len) + { + dynamic_cast(get_transform()).set_associated_data(ad, ad_len); + } + }; + +} + +#endif diff --git a/src/lib/filters/aead_filt/info.txt b/src/lib/filters/aead_filt/info.txt new file mode 100644 index 000000000..891f2c167 --- /dev/null +++ b/src/lib/filters/aead_filt/info.txt @@ -0,0 +1,5 @@ +define AEAD_FILTER 20131128 + + +aead + diff --git a/src/lib/filters/algo_filt.cpp b/src/lib/filters/algo_filt.cpp new file mode 100644 index 000000000..dbc46c7e6 --- /dev/null +++ b/src/lib/filters/algo_filt.cpp @@ -0,0 +1,135 @@ +/* +* Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher) : + buffer(DEFAULT_BUFFERSIZE) + { + cipher = stream_cipher; + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher, + const SymmetricKey& key) : + buffer(DEFAULT_BUFFERSIZE) + { + cipher = stream_cipher; + cipher->set_key(key); + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : + buffer(DEFAULT_BUFFERSIZE) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + cipher = af.make_stream_cipher(sc_name); + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, + const SymmetricKey& key) : + buffer(DEFAULT_BUFFERSIZE) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + cipher = af.make_stream_cipher(sc_name); + cipher->set_key(key); + } + +/* +* Set the IV of a stream cipher +*/ +void StreamCipher_Filter::set_iv(const InitializationVector& iv) + { + cipher->set_iv(iv.begin(), iv.length()); + } + +/* +* Write data into a StreamCipher_Filter +*/ +void StreamCipher_Filter::write(const byte input[], size_t length) + { + while(length) + { + size_t copied = std::min(length, buffer.size()); + cipher->cipher(input, &buffer[0], copied); + send(buffer, copied); + input += copied; + length -= copied; + } + } + +/* +* Hash_Filter Constructor +*/ +Hash_Filter::Hash_Filter(const std::string& algo_spec, + size_t len) : + OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + hash = af.make_hash_function(algo_spec); + } + +/* +* Complete a calculation by a Hash_Filter +*/ +void Hash_Filter::end_msg() + { + secure_vector output = hash->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +/* +* MAC_Filter Constructor +*/ +MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) : + OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + mac = af.make_mac(mac_name); + } + +/* +* MAC_Filter Constructor +*/ +MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, + size_t len) : OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + mac = af.make_mac(mac_name); + mac->set_key(key); + } + +/* +* Complete a calculation by a MAC_Filter +*/ +void MAC_Filter::end_msg() + { + secure_vector output = mac->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +} diff --git a/src/lib/filters/basefilt.cpp b/src/lib/filters/basefilt.cpp new file mode 100644 index 000000000..eace9cfd5 --- /dev/null +++ b/src/lib/filters/basefilt.cpp @@ -0,0 +1,70 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +void Keyed_Filter::set_iv(const InitializationVector& iv) + { + if(iv.length() != 0) + throw Invalid_IV_Length(name(), iv.length()); + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + if(f1) { attach(f1); incr_owns(); } + if(f2) { attach(f2); incr_owns(); } + if(f3) { attach(f3); incr_owns(); } + if(f4) { attach(f4); incr_owns(); } + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* filters[], size_t count) + { + for(size_t j = 0; j != count; ++j) + if(filters[j]) + { + attach(filters[j]); + incr_owns(); + } + } + +std::string Chain::name() const + { + return "Chain"; + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* filters[], size_t count) + { + set_next(filters, count); + } + +std::string Fork::name() const + { + return "Fork"; + } + +} diff --git a/src/lib/filters/basefilt.h b/src/lib/filters/basefilt.h new file mode 100644 index 000000000..be5cb7a26 --- /dev/null +++ b/src/lib/filters/basefilt.h @@ -0,0 +1,120 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* (C) 2013 Joel Low +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BASEFILT_H__ +#define BOTAN_BASEFILT_H__ + +#include +#include +#include + +namespace Botan { + +/** +* BitBucket is a filter which simply discards all inputs +*/ +struct BOTAN_DLL BitBucket : public Filter + { + void write(const byte[], size_t) {} + + std::string name() const { return "BitBucket"; } + }; + +/** +* This class represents Filter chains. A Filter chain is an ordered +* concatenation of Filters, the input to a Chain sequentially passes +* through all the Filters contained in the Chain. +*/ + +class BOTAN_DLL Chain : public Fanout_Filter + { + public: + void write(const byte input[], size_t length) { send(input, length); } + + std::string name() const; + + /** + * Construct a chain of up to four filters. The filters are set + * up in the same order as the arguments. + */ + Chain(Filter* = nullptr, Filter* = nullptr, + Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a chain from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Chain(Filter* filter_arr[], size_t length); + }; + +/** +* This class represents a fork filter, whose purpose is to fork the +* flow of data. It causes an input message to result in n messages at +* the end of the filter, where n is the number of forks. +*/ +class BOTAN_DLL Fork : public Fanout_Filter + { + public: + void write(const byte input[], size_t length) { send(input, length); } + void set_port(size_t n) { Fanout_Filter::set_port(n); } + + std::string name() const; + + /** + * Construct a Fork filter with up to four forks. + */ + Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Fork(Filter* filter_arr[], size_t length); + }; + +/** +* This class is a threaded version of the Fork filter. While this uses +* threads, the class itself is NOT thread-safe. This is meant as a drop- +* in replacement for Fork where performance gains are possible. +*/ +class BOTAN_DLL Threaded_Fork : public Fork + { + public: + std::string name() const; + + /** + * Construct a Threaded_Fork filter with up to four forks. + */ + Threaded_Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Threaded_Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Threaded_Fork(Filter* filter_arr[], size_t length); + + ~Threaded_Fork(); + + protected: + void set_next(Filter* f[], size_t n); + void send(const byte in[], size_t length); + + private: + void thread_delegate_work(const byte input[], size_t length); + void thread_entry(Filter* filter); + + std::vector> m_threads; + std::unique_ptr m_thread_data; + }; + +} + +#endif diff --git a/src/lib/filters/buf_filt.cpp b/src/lib/filters/buf_filt.cpp new file mode 100644 index 000000000..ca3fa9a3c --- /dev/null +++ b/src/lib/filters/buf_filt.cpp @@ -0,0 +1,103 @@ +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Buffered_Filter Constructor +*/ +Buffered_Filter::Buffered_Filter(size_t b, size_t f) : + main_block_mod(b), final_minimum(f) + { + if(main_block_mod == 0) + throw std::invalid_argument("main_block_mod == 0"); + + if(final_minimum > main_block_mod) + throw std::invalid_argument("final_minimum > main_block_mod"); + + buffer.resize(2 * main_block_mod); + buffer_pos = 0; + } + +/* +* Buffer input into blocks, trying to minimize copying +*/ +void Buffered_Filter::write(const byte input[], size_t input_size) + { + if(!input_size) + return; + + if(buffer_pos + input_size >= main_block_mod + final_minimum) + { + size_t to_copy = std::min(buffer.size() - buffer_pos, input_size); + + copy_mem(&buffer[buffer_pos], input, to_copy); + buffer_pos += to_copy; + + input += to_copy; + input_size -= to_copy; + + size_t total_to_consume = + round_down(std::min(buffer_pos, + buffer_pos + input_size - final_minimum), + main_block_mod); + + buffered_block(&buffer[0], total_to_consume); + + buffer_pos -= total_to_consume; + + copy_mem(&buffer[0], &buffer[total_to_consume], buffer_pos); + } + + if(input_size >= final_minimum) + { + size_t full_blocks = (input_size - final_minimum) / main_block_mod; + size_t to_copy = full_blocks * main_block_mod; + + if(to_copy) + { + buffered_block(input, to_copy); + + input += to_copy; + input_size -= to_copy; + } + } + + copy_mem(&buffer[buffer_pos], input, input_size); + buffer_pos += input_size; + } + +/* +* Finish/flush operation +*/ +void Buffered_Filter::end_msg() + { + if(buffer_pos < final_minimum) + throw std::runtime_error("Buffered filter end_msg without enough input"); + + size_t spare_blocks = (buffer_pos - final_minimum) / main_block_mod; + + if(spare_blocks) + { + size_t spare_bytes = main_block_mod * spare_blocks; + buffered_block(&buffer[0], spare_bytes); + buffered_final(&buffer[spare_bytes], buffer_pos - spare_bytes); + } + else + { + buffered_final(&buffer[0], buffer_pos); + } + + buffer_pos = 0; + } + +} diff --git a/src/lib/filters/buf_filt.h b/src/lib/filters/buf_filt.h new file mode 100644 index 000000000..9a3fc9a2b --- /dev/null +++ b/src/lib/filters/buf_filt.h @@ -0,0 +1,93 @@ +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BUFFERED_FILTER_H__ +#define BOTAN_BUFFERED_FILTER_H__ + +#include + +namespace Botan { + +/** +* Filter mixin that breaks input into blocks, useful for +* cipher modes +*/ +class BOTAN_DLL Buffered_Filter + { + public: + /** + * Write bytes into the buffered filter, which will them emit them + * in calls to buffered_block in the subclass + * @param in the input bytes + * @param length of in in bytes + */ + void write(const byte in[], size_t length); + + template + void write(const std::vector& in, size_t length) + { + write(&in[0], length); + } + + /** + * Finish a message, emitting to buffered_block and buffered_final + * Will throw an exception if less than final_minimum bytes were + * written into the filter. + */ + void end_msg(); + + /** + * Initialize a Buffered_Filter + * @param block_size the function buffered_block will be called + * with inputs which are a multiple of this size + * @param final_minimum the function buffered_final will be called + * with at least this many bytes. + */ + Buffered_Filter(size_t block_size, size_t final_minimum); + + virtual ~Buffered_Filter() {} + protected: + /** + * The block processor, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be a multiple + * of block_size + */ + virtual void buffered_block(const byte input[], size_t length) = 0; + + /** + * The final block, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be at least + * final_minimum bytes + */ + virtual void buffered_final(const byte input[], size_t length) = 0; + + /** + * @return block size of inputs + */ + size_t buffered_block_size() const { return main_block_mod; } + + /** + * @return current position in the buffer + */ + size_t current_position() const { return buffer_pos; } + + /** + * Reset the buffer position + */ + void buffer_reset() { buffer_pos = 0; } + private: + size_t main_block_mod, final_minimum; + + secure_vector buffer; + size_t buffer_pos; + }; + +} + +#endif diff --git a/src/lib/filters/codec_filt/b64_filt.cpp b/src/lib/filters/codec_filt/b64_filt.cpp new file mode 100644 index 000000000..b804b33c7 --- /dev/null +++ b/src/lib/filters/codec_filt/b64_filt.cpp @@ -0,0 +1,178 @@ +/* +* Base64 Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Base64_Encoder Constructor +*/ +Base64_Encoder::Base64_Encoder(bool breaks, size_t length, bool t_n) : + line_length(breaks ? length : 0), + trailing_newline(t_n && breaks), + in(48), + out(64), + position(0), + out_position(0) + { + } + +/* +* Encode and send a block +*/ +void Base64_Encoder::encode_and_send(const byte input[], size_t length, + bool final_inputs) + { + while(length) + { + const size_t proc = std::min(length, in.size()); + + size_t consumed = 0; + size_t produced = base64_encode(reinterpret_cast(&out[0]), input, + proc, consumed, final_inputs); + + do_output(&out[0], produced); + + // FIXME: s/proc/consumed/? + input += proc; + length -= proc; + } + } + +/* +* Handle the output +*/ +void Base64_Encoder::do_output(const byte input[], size_t length) + { + if(line_length == 0) + send(input, length); + else + { + size_t remaining = length, offset = 0; + while(remaining) + { + size_t sent = std::min(line_length - out_position, remaining); + send(input + offset, sent); + out_position += sent; + remaining -= sent; + offset += sent; + if(out_position == line_length) + { + send('\n'); + out_position = 0; + } + } + } + } + +/* +* Convert some data into Base64 +*/ +void Base64_Encoder::write(const byte input[], size_t length) + { + buffer_insert(in, position, input, length); + if(position + length >= in.size()) + { + encode_and_send(&in[0], in.size()); + input += (in.size() - position); + length -= (in.size() - position); + while(length >= in.size()) + { + encode_and_send(input, in.size()); + input += in.size(); + length -= in.size(); + } + copy_mem(&in[0], input, length); + position = 0; + } + position += length; + } + +/* +* Flush buffers +*/ +void Base64_Encoder::end_msg() + { + encode_and_send(&in[0], position, true); + + if(trailing_newline || (out_position && line_length)) + send('\n'); + + out_position = position = 0; + } + +/* +* Base64_Decoder Constructor +*/ +Base64_Decoder::Base64_Decoder(Decoder_Checking c) : + checking(c), in(64), out(48), position(0) + { + } + +/* +* Convert some data from Base64 +*/ +void Base64_Decoder::write(const byte input[], size_t length) + { + while(length) + { + size_t to_copy = std::min(length, in.size() - position); + copy_mem(&in[position], input, to_copy); + position += to_copy; + + size_t consumed = 0; + size_t written = base64_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + false, + checking != FULL_CHECK); + + send(out, written); + + if(consumed != position) + { + copy_mem(&in[0], &in[consumed], position - consumed); + position = position - consumed; + } + else + position = 0; + + length -= to_copy; + input += to_copy; + } + } + +/* +* Flush buffers +*/ +void Base64_Decoder::end_msg() + { + size_t consumed = 0; + size_t written = base64_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + true, + checking != FULL_CHECK); + + send(out, written); + + const bool not_full_bytes = consumed != position; + + position = 0; + + if(not_full_bytes) + throw std::invalid_argument("Base64_Decoder: Input not full bytes"); + } + +} diff --git a/src/lib/filters/codec_filt/b64_filt.h b/src/lib/filters/codec_filt/b64_filt.h new file mode 100644 index 000000000..dcb3cdbd5 --- /dev/null +++ b/src/lib/filters/codec_filt/b64_filt.h @@ -0,0 +1,88 @@ +/* +* Base64 Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BASE64_FILTER_H__ +#define BOTAN_BASE64_FILTER_H__ + +#include + +namespace Botan { + +/** +* This class represents a Base64 encoder. +*/ +class BOTAN_DLL Base64_Encoder : public Filter + { + public: + std::string name() const { return "Base64_Encoder"; } + + /** + * Input a part of a message to the encoder. + * @param input the message to input as a byte array + * @param length the length of the byte array input + */ + void write(const byte input[], size_t length); + + /** + * Inform the Encoder that the current message shall be closed. + */ + void end_msg(); + + /** + * Create a base64 encoder. + * @param breaks whether to use line breaks in the output + * @param length the length of the lines of the output + * @param t_n whether to use a trailing newline + */ + Base64_Encoder(bool breaks = false, size_t length = 72, + bool t_n = false); + private: + void encode_and_send(const byte input[], size_t length, + bool final_inputs = false); + void do_output(const byte output[], size_t length); + + const size_t line_length; + const bool trailing_newline; + std::vector in, out; + size_t position, out_position; + }; + +/** +* This object represents a Base64 decoder. +*/ +class BOTAN_DLL Base64_Decoder : public Filter + { + public: + std::string name() const { return "Base64_Decoder"; } + + /** + * Input a part of a message to the decoder. + * @param input the message to input as a byte array + * @param length the length of the byte array input + */ + void write(const byte input[], size_t length); + + /** + * Finish up the current message + */ + void end_msg(); + + /** + * Create a base64 decoder. + * @param checking the type of checking that shall be performed by + * the decoder + */ + Base64_Decoder(Decoder_Checking checking = NONE); + private: + const Decoder_Checking checking; + std::vector in, out; + size_t position; + }; + +} + +#endif diff --git a/src/lib/filters/codec_filt/hex_filt.cpp b/src/lib/filters/codec_filt/hex_filt.cpp new file mode 100644 index 000000000..e85bdb17e --- /dev/null +++ b/src/lib/filters/codec_filt/hex_filt.cpp @@ -0,0 +1,172 @@ +/* +* Hex Encoder/Decoder +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Size used for internal buffer in hex encoder/decoder +*/ +const size_t HEX_CODEC_BUFFER_SIZE = 256; + +/* +* Hex_Encoder Constructor +*/ +Hex_Encoder::Hex_Encoder(bool breaks, size_t length, Case c) : + casing(c), line_length(breaks ? length : 0) + { + in.resize(HEX_CODEC_BUFFER_SIZE); + out.resize(2*in.size()); + counter = position = 0; + } + +/* +* Hex_Encoder Constructor +*/ +Hex_Encoder::Hex_Encoder(Case c) : casing(c), line_length(0) + { + in.resize(HEX_CODEC_BUFFER_SIZE); + out.resize(2*in.size()); + counter = position = 0; + } + +/* +* Encode and send a block +*/ +void Hex_Encoder::encode_and_send(const byte block[], size_t length) + { + hex_encode(reinterpret_cast(&out[0]), + block, length, + casing == Uppercase); + + if(line_length == 0) + send(out, 2*length); + else + { + size_t remaining = 2*length, offset = 0; + while(remaining) + { + size_t sent = std::min(line_length - counter, remaining); + send(&out[offset], sent); + counter += sent; + remaining -= sent; + offset += sent; + if(counter == line_length) + { + send('\n'); + counter = 0; + } + } + } + } + +/* +* Convert some data into hex format +*/ +void Hex_Encoder::write(const byte input[], size_t length) + { + buffer_insert(in, position, input, length); + if(position + length >= in.size()) + { + encode_and_send(&in[0], in.size()); + input += (in.size() - position); + length -= (in.size() - position); + while(length >= in.size()) + { + encode_and_send(input, in.size()); + input += in.size(); + length -= in.size(); + } + copy_mem(&in[0], input, length); + position = 0; + } + position += length; + } + +/* +* Flush buffers +*/ +void Hex_Encoder::end_msg() + { + encode_and_send(&in[0], position); + if(counter && line_length) + send('\n'); + counter = position = 0; + } + +/* +* Hex_Decoder Constructor +*/ +Hex_Decoder::Hex_Decoder(Decoder_Checking c) : checking(c) + { + in.resize(HEX_CODEC_BUFFER_SIZE); + out.resize(in.size() / 2); + position = 0; + } + +/* +* Convert some data from hex format +*/ +void Hex_Decoder::write(const byte input[], size_t length) + { + while(length) + { + size_t to_copy = std::min(length, in.size() - position); + copy_mem(&in[position], input, to_copy); + position += to_copy; + + size_t consumed = 0; + size_t written = hex_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + checking != FULL_CHECK); + + send(out, written); + + if(consumed != position) + { + copy_mem(&in[0], &in[consumed], position - consumed); + position = position - consumed; + } + else + position = 0; + + length -= to_copy; + input += to_copy; + } + } + +/* +* Flush buffers +*/ +void Hex_Decoder::end_msg() + { + size_t consumed = 0; + size_t written = hex_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + checking != FULL_CHECK); + + send(out, written); + + const bool not_full_bytes = consumed != position; + + position = 0; + + if(not_full_bytes) + throw std::invalid_argument("Hex_Decoder: Input not full bytes"); + } + +} diff --git a/src/lib/filters/codec_filt/hex_filt.h b/src/lib/filters/codec_filt/hex_filt.h new file mode 100644 index 000000000..dbe6b9bae --- /dev/null +++ b/src/lib/filters/codec_filt/hex_filt.h @@ -0,0 +1,81 @@ +/* +* Hex Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HEX_FILTER_H__ +#define BOTAN_HEX_FILTER_H__ + +#include + +namespace Botan { + +/** +* Converts arbitrary binary data to hex strings, optionally with +* newlines inserted +*/ +class BOTAN_DLL Hex_Encoder : public Filter + { + public: + /** + * Whether to use uppercase or lowercase letters for the encoded string. + */ + enum Case { Uppercase, Lowercase }; + + std::string name() const { return "Hex_Encoder"; } + + void write(const byte in[], size_t length); + void end_msg(); + + /** + * Create a hex encoder. + * @param the_case the case to use in the encoded strings. + */ + Hex_Encoder(Case the_case); + + /** + * Create a hex encoder. + * @param newlines should newlines be used + * @param line_length if newlines are used, how long are lines + * @param the_case the case to use in the encoded strings + */ + Hex_Encoder(bool newlines = false, + size_t line_length = 72, + Case the_case = Uppercase); + private: + void encode_and_send(const byte[], size_t); + + const Case casing; + const size_t line_length; + std::vector in, out; + size_t position, counter; + }; + +/** +* Converts hex strings to bytes +*/ +class BOTAN_DLL Hex_Decoder : public Filter + { + public: + std::string name() const { return "Hex_Decoder"; } + + void write(const byte[], size_t); + void end_msg(); + + /** + * Construct a Hex Decoder using the specified + * character checking. + * @param checking the checking to use during decoding. + */ + Hex_Decoder(Decoder_Checking checking = NONE); + private: + const Decoder_Checking checking; + std::vector in, out; + size_t position; + }; + +} + +#endif diff --git a/src/lib/filters/codec_filt/info.txt b/src/lib/filters/codec_filt/info.txt new file mode 100644 index 000000000..58fcfbb4b --- /dev/null +++ b/src/lib/filters/codec_filt/info.txt @@ -0,0 +1,5 @@ +define CODEC_FILTERS 20131128 + + +filters + diff --git a/src/lib/filters/compression/bzip2/bzip2.cpp b/src/lib/filters/compression/bzip2/bzip2.cpp new file mode 100644 index 000000000..a7990d2c2 --- /dev/null +++ b/src/lib/filters/compression/bzip2/bzip2.cpp @@ -0,0 +1,298 @@ +/* +* Bzip Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* 2006 Matt Johnston +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#include +#include +#include +#define BZ_NO_STDIO +#include + +namespace Botan { + +namespace { + +/* +* Allocation Information for Bzip +*/ +class Bzip_Alloc_Info + { + public: + std::map current_allocs; + }; + +/* +* Allocation Function for Bzip +*/ +void* bzip_malloc(void* info_ptr, int n, int size) + { + Bzip_Alloc_Info* info = static_cast(info_ptr); + + const size_t total_sz = n * size; + + void* ptr = std::malloc(total_sz); + info->current_allocs[ptr] = total_sz; + return ptr; + } + +/* +* Allocation Function for Bzip +*/ +void bzip_free(void* info_ptr, void* ptr) + { + Bzip_Alloc_Info* info = static_cast(info_ptr); + auto i = info->current_allocs.find(ptr); + if(i == info->current_allocs.end()) + throw Invalid_Argument("bzip_free: Got pointer not allocated by us"); + + std::memset(ptr, 0, i->second); + std::free(ptr); + } + +} + +/** +* Wrapper Type for Bzip2 Stream +*/ +class Bzip_Stream + { + public: + /** + * Underlying stream + */ + bz_stream stream; + + /** + * Constructor + */ + Bzip_Stream() + { + std::memset(&stream, 0, sizeof(bz_stream)); + stream.bzalloc = bzip_malloc; + stream.bzfree = bzip_free; + stream.opaque = new Bzip_Alloc_Info; + } + + /** + * Destructor + */ + ~Bzip_Stream() + { + Bzip_Alloc_Info* info = static_cast(stream.opaque); + delete info; + std::memset(&stream, 0, sizeof(bz_stream)); + } + }; + +/* +* Bzip_Compression Constructor +*/ +Bzip_Compression::Bzip_Compression(size_t l) : + level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE) + { + bz = 0; + } + +/* +* Start Compressing with Bzip +*/ +void Bzip_Compression::start_msg() + { + clear(); + bz = new Bzip_Stream; + if(BZ2_bzCompressInit(&(bz->stream), level, 0, 0) != BZ_OK) + throw Memory_Exhaustion(); + } + +/* +* Compress Input with Bzip +*/ +void Bzip_Compression::write(const byte input[], size_t length) + { + bz->stream.next_in = reinterpret_cast(const_cast(input)); + bz->stream.avail_in = length; + + while(bz->stream.avail_in != 0) + { + bz->stream.next_out = reinterpret_cast(&buffer[0]); + bz->stream.avail_out = buffer.size(); + BZ2_bzCompress(&(bz->stream), BZ_RUN); + send(buffer, buffer.size() - bz->stream.avail_out); + } + } + +/* +* Finish Compressing with Bzip +*/ +void Bzip_Compression::end_msg() + { + bz->stream.next_in = 0; + bz->stream.avail_in = 0; + + int rc = BZ_OK; + while(rc != BZ_STREAM_END) + { + bz->stream.next_out = reinterpret_cast(&buffer[0]); + bz->stream.avail_out = buffer.size(); + rc = BZ2_bzCompress(&(bz->stream), BZ_FINISH); + send(buffer, buffer.size() - bz->stream.avail_out); + } + clear(); + } + +/* +* Flush the Bzip Compressor +*/ +void Bzip_Compression::flush() + { + bz->stream.next_in = 0; + bz->stream.avail_in = 0; + + int rc = BZ_OK; + while(rc != BZ_RUN_OK) + { + bz->stream.next_out = reinterpret_cast(&buffer[0]); + bz->stream.avail_out = buffer.size(); + rc = BZ2_bzCompress(&(bz->stream), BZ_FLUSH); + send(buffer, buffer.size() - bz->stream.avail_out); + } + } + +/* +* Clean up Compression Context +*/ +void Bzip_Compression::clear() + { + zeroise(buffer); + + if(bz) + { + BZ2_bzCompressEnd(&(bz->stream)); + delete bz; + bz = 0; + } + } + +/* +* Bzip_Decompression Constructor +*/ +Bzip_Decompression::Bzip_Decompression(bool s) : + small_mem(s), buffer(DEFAULT_BUFFERSIZE) + { + no_writes = true; + bz = 0; + } + +/* +* Decompress Input with Bzip +*/ +void Bzip_Decompression::write(const byte input_arr[], size_t length) + { + if(length) no_writes = false; + + char* input = reinterpret_cast(const_cast(input_arr)); + + bz->stream.next_in = input; + bz->stream.avail_in = length; + + while(bz->stream.avail_in != 0) + { + bz->stream.next_out = reinterpret_cast(&buffer[0]); + bz->stream.avail_out = buffer.size(); + + int rc = BZ2_bzDecompress(&(bz->stream)); + + if(rc != BZ_OK && rc != BZ_STREAM_END) + { + clear(); + + if(rc == BZ_DATA_ERROR) + throw Decoding_Error("Bzip_Decompression: Data integrity error"); + else if(rc == BZ_DATA_ERROR_MAGIC) + throw Decoding_Error("Bzip_Decompression: Invalid input"); + else if(rc == BZ_MEM_ERROR) + throw Memory_Exhaustion(); + else + throw std::runtime_error("Bzip2 decompression: Unknown error"); + } + + send(buffer, buffer.size() - bz->stream.avail_out); + + if(rc == BZ_STREAM_END) + { + size_t read_from_block = length - bz->stream.avail_in; + start_msg(); + bz->stream.next_in = input + read_from_block; + bz->stream.avail_in = length - read_from_block; + input += read_from_block; + length -= read_from_block; + } + } + } + +/* +* Start Decompressing with Bzip +*/ +void Bzip_Decompression::start_msg() + { + clear(); + bz = new Bzip_Stream; + + if(BZ2_bzDecompressInit(&(bz->stream), 0, small_mem) != BZ_OK) + throw Memory_Exhaustion(); + + no_writes = true; + } + +/* +* Finish Decompressing with Bzip +*/ +void Bzip_Decompression::end_msg() + { + if(no_writes) return; + bz->stream.next_in = 0; + bz->stream.avail_in = 0; + + int rc = BZ_OK; + while(rc != BZ_STREAM_END) + { + bz->stream.next_out = reinterpret_cast(&buffer[0]); + bz->stream.avail_out = buffer.size(); + rc = BZ2_bzDecompress(&(bz->stream)); + + if(rc != BZ_OK && rc != BZ_STREAM_END) + { + clear(); + throw Decoding_Error("Bzip_Decompression: Error finalizing"); + } + + send(buffer, buffer.size() - bz->stream.avail_out); + } + + clear(); + } + +/* +* Clean up Decompression Context +*/ +void Bzip_Decompression::clear() + { + zeroise(buffer); + + if(bz) + { + BZ2_bzDecompressEnd(&(bz->stream)); + delete bz; + bz = 0; + } + } + +} diff --git a/src/lib/filters/compression/bzip2/bzip2.h b/src/lib/filters/compression/bzip2/bzip2.h new file mode 100644 index 000000000..2505cf54e --- /dev/null +++ b/src/lib/filters/compression/bzip2/bzip2.h @@ -0,0 +1,65 @@ +/* +* Bzip Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BZIP2_H__ +#define BOTAN_BZIP2_H__ + +#include + +namespace Botan { + +/** +* Bzip Compression Filter +*/ +class BOTAN_DLL Bzip_Compression : public Filter + { + public: + std::string name() const { return "Bzip_Compression"; } + + void write(const byte input[], size_t length); + void start_msg(); + void end_msg(); + + void flush(); + + Bzip_Compression(size_t = 9); + ~Bzip_Compression() { clear(); } + private: + void clear(); + + const size_t level; + secure_vector buffer; + class Bzip_Stream* bz; + }; + +/** +* Bzip Decompression Filter +*/ +class BOTAN_DLL Bzip_Decompression : public Filter + { + public: + std::string name() const { return "Bzip_Decompression"; } + + void write(const byte input[], size_t length); + void start_msg(); + void end_msg(); + + Bzip_Decompression(bool = false); + ~Bzip_Decompression() { clear(); } + private: + void clear(); + + const bool small_mem; + secure_vector buffer; + class Bzip_Stream* bz; + bool no_writes; + }; + +} + +#endif diff --git a/src/lib/filters/compression/bzip2/info.txt b/src/lib/filters/compression/bzip2/info.txt new file mode 100644 index 000000000..7c0f2aafc --- /dev/null +++ b/src/lib/filters/compression/bzip2/info.txt @@ -0,0 +1,11 @@ +define COMPRESSOR_BZIP2 20131128 + +load_on request + + +all -> bz2 + + + +filters + diff --git a/src/lib/filters/compression/lzma/info.txt b/src/lib/filters/compression/lzma/info.txt new file mode 100644 index 000000000..ccd7a7600 --- /dev/null +++ b/src/lib/filters/compression/lzma/info.txt @@ -0,0 +1,11 @@ +define COMPRESSOR_LZMA 20131128 + +load_on request + + +all -> lzma + + + +filters + diff --git a/src/lib/filters/compression/lzma/lzma.cpp b/src/lib/filters/compression/lzma/lzma.cpp new file mode 100644 index 000000000..eaf18b4bf --- /dev/null +++ b/src/lib/filters/compression/lzma/lzma.cpp @@ -0,0 +1,327 @@ +/* +* Lzma Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* 2006 Matt Johnston +* 2012 Vojtech Kral +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Allocation Information for Lzma +*/ +class Lzma_Alloc_Info + { + public: + std::map current_allocs; + }; + +/* +* Allocation Function for Lzma +*/ +void* lzma_malloc(void *opaque, size_t /*nmemb*/, size_t size) + { + Lzma_Alloc_Info* info = static_cast(opaque); + void* ptr = std::malloc(size); // It is guaranteed by liblzma doc that nmemb is always set to 1 + info->current_allocs[ptr] = size; + return ptr; + } + +/* +* Allocation Function for Lzma +*/ +void lzma_free(void *opaque, void *ptr) + { + if(!ptr) return; // liblzma sometimes does pass zero ptr + + Lzma_Alloc_Info* info = static_cast(opaque); + auto i = info->current_allocs.find(ptr); + if(i == info->current_allocs.end()) + throw Invalid_Argument("lzma_free: Got pointer not allocated by us"); + + std::memset(ptr, 0, i->second); + std::free(ptr); + } + +} + +/** +* Wrapper Type for lzma_stream +*/ +class Lzma_Stream + { + public: + /** + * Underlying stream + */ + lzma_stream stream; + + /** + * Constructor + */ + Lzma_Stream() : + stream(LZMA_STREAM_INIT) + { + stream.allocator = new lzma_allocator; + stream.allocator->alloc = lzma_malloc; + stream.allocator->free = lzma_free; + stream.allocator->opaque = new Lzma_Alloc_Info; + } + + /** + * Destructor + */ + ~Lzma_Stream() + { + Lzma_Alloc_Info* info = static_cast(stream.allocator->opaque); + delete info; + delete stream.allocator; + std::memset(&stream, 0, sizeof(lzma_stream)); + } + }; + +/* +* Lzma_Compression Constructor +*/ +Lzma_Compression::Lzma_Compression(size_t l) : + level((l >= 9) ? 9 : l), + buffer(DEFAULT_BUFFERSIZE), + lzma(0) + { + } + +/* +* Start Compressing with Lzma +*/ +void Lzma_Compression::start_msg() + { + clear(); + lzma = new Lzma_Stream; + + lzma_ret ret = lzma_easy_encoder(&(lzma->stream), level, LZMA_CHECK_CRC64); + + if(ret == LZMA_MEM_ERROR) + throw Memory_Exhaustion(); + else if(ret != LZMA_OK) + throw Invalid_Argument("Bad setting in lzma_easy_encoder"); + } + +/* +* Compress Input with Lzma +*/ +void Lzma_Compression::write(const byte input[], size_t length) + { + lzma->stream.next_in = static_cast(input); + lzma->stream.avail_in = length; + + while(lzma->stream.avail_in != 0) + { + lzma->stream.next_out = static_cast(&buffer[0]); + lzma->stream.avail_out = buffer.size(); + + lzma_ret ret = lzma_code(&(lzma->stream), LZMA_RUN); + + if(ret == LZMA_MEM_ERROR) + throw Memory_Exhaustion(); + else if (ret != LZMA_OK) + throw std::runtime_error("Lzma compression: Error writing"); + + send(&buffer[0], buffer.size() - lzma->stream.avail_out); + } + } + +/* +* Finish Compressing with Lzma +*/ +void Lzma_Compression::end_msg() + { + lzma->stream.next_in = 0; + lzma->stream.avail_in = 0; + + int ret = LZMA_OK; + while(ret != LZMA_STREAM_END) + { + lzma->stream.next_out = reinterpret_cast(&buffer[0]); + lzma->stream.avail_out = buffer.size(); + + ret = lzma_code(&(lzma->stream), LZMA_FINISH); + send(&buffer[0], buffer.size() - lzma->stream.avail_out); + } + + clear(); + } + +/* +* Flush the Lzma Compressor +*/ +void Lzma_Compression::flush() + { + lzma->stream.next_in = 0; + lzma->stream.avail_in = 0; + + while(true) + { + lzma->stream.next_out = reinterpret_cast(&buffer[0]); + lzma->stream.avail_out = buffer.size(); + + lzma_ret ret = lzma_code(&(lzma->stream), LZMA_FULL_FLUSH); + + if(ret == LZMA_MEM_ERROR) + throw Memory_Exhaustion(); + else if (ret != LZMA_OK && ret != LZMA_STREAM_END) + throw std::runtime_error("Lzma compression: Error flushing"); + + send(&buffer[0], buffer.size() - lzma->stream.avail_out); + + if(lzma->stream.avail_out == buffer.size()) + break; + } + } + +/* +* Clean up Compression Context +*/ +void Lzma_Compression::clear() + { + zeroise(buffer); + + if(lzma) + { + lzma_end(&(lzma->stream)); + delete lzma; + lzma = 0; + } + } + +/* +* Lzma_Decompression Constructor +*/ +Lzma_Decompression::Lzma_Decompression() : + buffer(DEFAULT_BUFFERSIZE), + lzma(0), + no_writes(true) + { + } + +/* +* Start Decompressing with Lzma +*/ +void Lzma_Decompression::start_msg() + { + clear(); + lzma = new Lzma_Stream; + + lzma_ret ret = lzma_stream_decoder(&(lzma->stream), UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED); + + if(ret == LZMA_MEM_ERROR) + throw Memory_Exhaustion(); + else if(ret != LZMA_OK) + throw Invalid_Argument("Bad setting in lzma_stream_decoder"); + } + +/* +* Decompress Input with Lzma +*/ +void Lzma_Decompression::write(const byte input_arr[], size_t length) + { + if(length) no_writes = false; + + const uint8_t* input = reinterpret_cast(input_arr); + + lzma->stream.next_in = input; + lzma->stream.avail_in = length; + + while(lzma->stream.avail_in != 0) + { + lzma->stream.next_out = reinterpret_cast(&buffer[0]); + lzma->stream.avail_out = buffer.size(); + + lzma_ret ret = lzma_code(&(lzma->stream), LZMA_RUN); + + if(ret != LZMA_OK && ret != LZMA_STREAM_END) + { + clear(); + if(ret == LZMA_DATA_ERROR) + throw Decoding_Error("Lzma_Decompression: Data integrity error"); + else if(ret == LZMA_MEM_ERROR) + throw Memory_Exhaustion(); + else + throw std::runtime_error("Lzma decompression: Unknown error"); + } + + send(&buffer[0], buffer.size() - lzma->stream.avail_out); + + if(ret == LZMA_STREAM_END) + { + size_t read_from_block = length - lzma->stream.avail_in; + start_msg(); + + lzma->stream.next_in = input + read_from_block; + lzma->stream.avail_in = length - read_from_block; + + input += read_from_block; + length -= read_from_block; + } + } + } + +/* +* Finish Decompressing with Lzma +*/ +void Lzma_Decompression::end_msg() + { + if(no_writes) return; + lzma->stream.next_in = 0; + lzma->stream.avail_in = 0; + + int ret = LZMA_OK; + + while(ret != LZMA_STREAM_END) + { + lzma->stream.next_out = reinterpret_cast(&buffer[0]); + lzma->stream.avail_out = buffer.size(); + ret = lzma_code(&(lzma->stream), LZMA_FINISH); + + if(ret != LZMA_OK && ret != LZMA_STREAM_END) + { + clear(); + throw Decoding_Error("Lzma_Decompression: Error finalizing"); + } + + send(&buffer[0], buffer.size() - lzma->stream.avail_out); + } + + clear(); + } + +/* +* Clean up Decompression Context +*/ +void Lzma_Decompression::clear() + { + zeroise(buffer); + + no_writes = true; + + if(lzma) + { + lzma_end(&(lzma->stream)); + delete lzma; + lzma = 0; + } + } + +} diff --git a/src/lib/filters/compression/lzma/lzma.h b/src/lib/filters/compression/lzma/lzma.h new file mode 100644 index 000000000..33e12d580 --- /dev/null +++ b/src/lib/filters/compression/lzma/lzma.h @@ -0,0 +1,74 @@ +/* +* Lzma Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* 2012 Vojtech Kral +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LZMA_H__ +#define BOTAN_LZMA_H__ + +#include + +namespace Botan { + +/** +* Lzma Compression Filter +*/ +class BOTAN_DLL Lzma_Compression : public Filter + { + public: + std::string name() const { return "Lzma_Compression"; } + + void write(const byte input[], size_t length); + void start_msg(); + void end_msg(); + + /** + * Flush the compressor + */ + void flush(); + + /** + * @param level how much effort to use on compressing (0 to 9); + * higher levels are slower but tend to give better + * compression + */ + Lzma_Compression(size_t level = 6); + + ~Lzma_Compression() { clear(); } + private: + void clear(); + const size_t level; + + secure_vector buffer; + class Lzma_Stream* lzma; + }; + +/** +* Lzma Decompression Filter +*/ +class BOTAN_DLL Lzma_Decompression : public Filter + { + public: + std::string name() const { return "Lzma_Decompression"; } + + void write(const byte input[], size_t length); + void start_msg(); + void end_msg(); + + Lzma_Decompression(); + ~Lzma_Decompression() { clear(); } + private: + void clear(); + + secure_vector buffer; + class Lzma_Stream* lzma; + bool no_writes; + }; + +} + +#endif diff --git a/src/lib/filters/compression/zlib/info.txt b/src/lib/filters/compression/zlib/info.txt new file mode 100644 index 000000000..d05e407d2 --- /dev/null +++ b/src/lib/filters/compression/zlib/info.txt @@ -0,0 +1,11 @@ +define COMPRESSOR_ZLIB 20131128 + +load_on request + + +all -> z + + + +filters + diff --git a/src/lib/filters/compression/zlib/zlib.cpp b/src/lib/filters/compression/zlib/zlib.cpp new file mode 100644 index 000000000..4a0b2c8b4 --- /dev/null +++ b/src/lib/filters/compression/zlib/zlib.cpp @@ -0,0 +1,318 @@ +/* +* Zlib Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* 2006 Matt Johnston +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Allocation Information for Zlib +*/ +class Zlib_Alloc_Info + { + public: + std::map current_allocs; + }; + +/* +* Allocation Function for Zlib +*/ +void* zlib_malloc(void* info_ptr, unsigned int n, unsigned int size) + { + Zlib_Alloc_Info* info = static_cast(info_ptr); + + const size_t total_sz = n * size; + + void* ptr = std::malloc(total_sz); + info->current_allocs[ptr] = total_sz; + return ptr; + } + +/* +* Allocation Function for Zlib +*/ +void zlib_free(void* info_ptr, void* ptr) + { + Zlib_Alloc_Info* info = static_cast(info_ptr); + auto i = info->current_allocs.find(ptr); + if(i == info->current_allocs.end()) + throw Invalid_Argument("zlib_free: Got pointer not allocated by us"); + + std::memset(ptr, 0, i->second); + std::free(ptr); + } + +} + +/** +* Wrapper Type for Zlib z_stream +*/ +class Zlib_Stream + { + public: + /** + * Underlying stream + */ + z_stream stream; + + /** + * Constructor + */ + Zlib_Stream() + { + std::memset(&stream, 0, sizeof(z_stream)); + stream.zalloc = zlib_malloc; + stream.zfree = zlib_free; + stream.opaque = new Zlib_Alloc_Info; + } + + /** + * Destructor + */ + ~Zlib_Stream() + { + Zlib_Alloc_Info* info = static_cast(stream.opaque); + delete info; + std::memset(&stream, 0, sizeof(z_stream)); + } + }; + +/* +* Zlib_Compression Constructor +*/ +Zlib_Compression::Zlib_Compression(size_t l, bool raw_deflate) : + level((l >= 9) ? 9 : l), + raw_deflate(raw_deflate), + buffer(DEFAULT_BUFFERSIZE), + zlib(0) + { + } + +/* +* Start Compressing with Zlib +*/ +void Zlib_Compression::start_msg() + { + clear(); + zlib = new Zlib_Stream; + + int res = deflateInit2(&(zlib->stream), + level, + Z_DEFLATED, + (raw_deflate ? -15 : 15), + 8, + Z_DEFAULT_STRATEGY); + + if(res == Z_STREAM_ERROR) + throw Invalid_Argument("Bad setting in deflateInit2"); + else if(res != Z_OK) + throw Memory_Exhaustion(); + } + +/* +* Compress Input with Zlib +*/ +void Zlib_Compression::write(const byte input[], size_t length) + { + zlib->stream.next_in = static_cast(const_cast(input)); + zlib->stream.avail_in = length; + + while(zlib->stream.avail_in != 0) + { + zlib->stream.next_out = static_cast(&buffer[0]); + zlib->stream.avail_out = buffer.size(); + deflate(&(zlib->stream), Z_NO_FLUSH); + send(&buffer[0], buffer.size() - zlib->stream.avail_out); + } + } + +/* +* Finish Compressing with Zlib +*/ +void Zlib_Compression::end_msg() + { + zlib->stream.next_in = 0; + zlib->stream.avail_in = 0; + + int rc = Z_OK; + while(rc != Z_STREAM_END) + { + zlib->stream.next_out = reinterpret_cast(&buffer[0]); + zlib->stream.avail_out = buffer.size(); + + rc = deflate(&(zlib->stream), Z_FINISH); + send(&buffer[0], buffer.size() - zlib->stream.avail_out); + } + + clear(); + } + +/* +* Flush the Zlib Compressor +*/ +void Zlib_Compression::flush() + { + zlib->stream.next_in = 0; + zlib->stream.avail_in = 0; + + while(true) + { + zlib->stream.avail_out = buffer.size(); + zlib->stream.next_out = reinterpret_cast(&buffer[0]); + + deflate(&(zlib->stream), Z_FULL_FLUSH); + send(&buffer[0], buffer.size() - zlib->stream.avail_out); + + if(zlib->stream.avail_out == buffer.size()) + break; + } + } + +/* +* Clean up Compression Context +*/ +void Zlib_Compression::clear() + { + zeroise(buffer); + + if(zlib) + { + deflateEnd(&(zlib->stream)); + delete zlib; + zlib = 0; + } + } + +/* +* Zlib_Decompression Constructor +*/ +Zlib_Decompression::Zlib_Decompression(bool raw_deflate) : + raw_deflate(raw_deflate), + buffer(DEFAULT_BUFFERSIZE), + zlib(0), + no_writes(true) + { + } + +/* +* Start Decompressing with Zlib +*/ +void Zlib_Decompression::start_msg() + { + clear(); + zlib = new Zlib_Stream; + + if(inflateInit2(&(zlib->stream), (raw_deflate ? -15 : 15)) != Z_OK) + throw Memory_Exhaustion(); + } + +/* +* Decompress Input with Zlib +*/ +void Zlib_Decompression::write(const byte input_arr[], size_t length) + { + if(length) no_writes = false; + + // non-const needed by zlib api :( + Bytef* input = reinterpret_cast(const_cast(input_arr)); + + zlib->stream.next_in = input; + zlib->stream.avail_in = length; + + while(zlib->stream.avail_in != 0) + { + zlib->stream.next_out = reinterpret_cast(&buffer[0]); + zlib->stream.avail_out = buffer.size(); + + int rc = inflate(&(zlib->stream), Z_SYNC_FLUSH); + + if(rc != Z_OK && rc != Z_STREAM_END) + { + clear(); + if(rc == Z_DATA_ERROR) + throw Decoding_Error("Zlib_Decompression: Data integrity error"); + else if(rc == Z_NEED_DICT) + throw Decoding_Error("Zlib_Decompression: Need preset dictionary"); + else if(rc == Z_MEM_ERROR) + throw Memory_Exhaustion(); + else + throw std::runtime_error("Zlib decompression: Unknown error"); + } + + send(&buffer[0], buffer.size() - zlib->stream.avail_out); + + if(rc == Z_STREAM_END) + { + size_t read_from_block = length - zlib->stream.avail_in; + start_msg(); + + zlib->stream.next_in = input + read_from_block; + zlib->stream.avail_in = length - read_from_block; + + input += read_from_block; + length -= read_from_block; + } + } + } + +/* +* Finish Decompressing with Zlib +*/ +void Zlib_Decompression::end_msg() + { + if(no_writes) return; + zlib->stream.next_in = 0; + zlib->stream.avail_in = 0; + + int rc = Z_OK; + + while(rc != Z_STREAM_END) + { + zlib->stream.next_out = reinterpret_cast(&buffer[0]); + zlib->stream.avail_out = buffer.size(); + rc = inflate(&(zlib->stream), Z_SYNC_FLUSH); + + if(rc != Z_OK && rc != Z_STREAM_END) + { + clear(); + throw Decoding_Error("Zlib_Decompression: Error finalizing"); + } + + send(&buffer[0], buffer.size() - zlib->stream.avail_out); + } + + clear(); + } + +/* +* Clean up Decompression Context +*/ +void Zlib_Decompression::clear() + { + zeroise(buffer); + + no_writes = true; + + if(zlib) + { + inflateEnd(&(zlib->stream)); + delete zlib; + zlib = 0; + } + } + +} diff --git a/src/lib/filters/compression/zlib/zlib.h b/src/lib/filters/compression/zlib/zlib.h new file mode 100644 index 000000000..c4d21a250 --- /dev/null +++ b/src/lib/filters/compression/zlib/zlib.h @@ -0,0 +1,78 @@ +/* +* Zlib Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ZLIB_H__ +#define BOTAN_ZLIB_H__ + +#include + +namespace Botan { + +/** +* Zlib Compression Filter +*/ +class BOTAN_DLL Zlib_Compression : public Filter + { + public: + std::string name() const { return "Zlib_Compression"; } + + void write(const byte input[], size_t length); + void start_msg(); + void end_msg(); + + /** + * Flush the compressor + */ + void flush(); + + /** + * @param level how much effort to use on compressing (0 to 9); + * higher levels are slower but tend to give better + * compression + * @param raw_deflate if true no zlib header/trailer will be used + */ + Zlib_Compression(size_t level = 6, + bool raw_deflate = false); + + ~Zlib_Compression() { clear(); } + private: + void clear(); + const size_t level; + const bool raw_deflate; + + secure_vector buffer; + class Zlib_Stream* zlib; + }; + +/** +* Zlib Decompression Filter +*/ +class BOTAN_DLL Zlib_Decompression : public Filter + { + public: + std::string name() const { return "Zlib_Decompression"; } + + void write(const byte input[], size_t length); + void start_msg(); + void end_msg(); + + Zlib_Decompression(bool raw_deflate = false); + ~Zlib_Decompression() { clear(); } + private: + void clear(); + + const bool raw_deflate; + + secure_vector buffer; + class Zlib_Stream* zlib; + bool no_writes; + }; + +} + +#endif diff --git a/src/lib/filters/data_snk.cpp b/src/lib/filters/data_snk.cpp new file mode 100644 index 000000000..2903e5e1f --- /dev/null +++ b/src/lib/filters/data_snk.cpp @@ -0,0 +1,63 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Write to a stream +*/ +void DataSink_Stream::write(const byte out[], size_t length) + { + sink.write(reinterpret_cast(out), length); + if(!sink.good()) + throw Stream_IO_Error("DataSink_Stream: Failure writing to " + + identifier); + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(std::ostream& out, + const std::string& name) : + identifier(name), + sink_p(nullptr), + sink(out) + { + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(const std::string& path, + bool use_binary) : + identifier(path), + sink_p(new std::ofstream( + path.c_str(), + use_binary ? std::ios::binary : std::ios::out)), + sink(*sink_p) + { + if(!sink.good()) + { + delete sink_p; + throw Stream_IO_Error("DataSink_Stream: Failure opening " + path); + } + } + +/* +* DataSink_Stream Destructor +*/ +DataSink_Stream::~DataSink_Stream() + { + delete sink_p; + } + +} diff --git a/src/lib/filters/data_snk.h b/src/lib/filters/data_snk.h new file mode 100644 index 000000000..6b9da0b4d --- /dev/null +++ b/src/lib/filters/data_snk.h @@ -0,0 +1,67 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DATA_SINK_H__ +#define BOTAN_DATA_SINK_H__ + +#include +#include + +namespace Botan { + +/** +* This class represents abstract data sink objects. +*/ +class BOTAN_DLL DataSink : public Filter + { + public: + bool attachable() { return false; } + DataSink() {} + virtual ~DataSink() {} + + DataSink& operator=(const DataSink&) = delete; + DataSink(const DataSink&) = delete; + }; + +/** +* This class represents a data sink which writes its output to a stream. +*/ +class BOTAN_DLL DataSink_Stream : public DataSink + { + public: + std::string name() const { return identifier; } + + void write(const byte[], size_t); + + /** + * Construct a DataSink_Stream from a stream. + * @param stream the stream to write to + * @param name identifier + */ + DataSink_Stream(std::ostream& stream, + const std::string& name = ""); + + /** + * Construct a DataSink_Stream from a stream. + * @param pathname the name of the file to open a stream to + * @param use_binary indicates whether to treat the file + * as a binary file or not + */ + DataSink_Stream(const std::string& pathname, + bool use_binary = false); + + ~DataSink_Stream(); + private: + const std::string identifier; + + std::ostream* sink_p; + std::ostream& sink; + }; + +} + +#endif diff --git a/src/lib/filters/data_src.cpp b/src/lib/filters/data_src.cpp new file mode 100644 index 000000000..cc100ab13 --- /dev/null +++ b/src/lib/filters/data_src.cpp @@ -0,0 +1,191 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Read a single byte from the DataSource +*/ +size_t DataSource::read_byte(byte& out) + { + return read(&out, 1); + } + +/* +* Peek a single byte from the DataSource +*/ +size_t DataSource::peek_byte(byte& out) const + { + return peek(&out, 1, 0); + } + +/* +* Discard the next N bytes of the data +*/ +size_t DataSource::discard_next(size_t n) + { + size_t discarded = 0; + byte dummy; + for(size_t j = 0; j != n; ++j) + discarded += read_byte(dummy); + return discarded; + } + +/* +* Read from a memory buffer +*/ +size_t DataSource_Memory::read(byte out[], size_t length) + { + size_t got = std::min(source.size() - offset, length); + copy_mem(out, &source[offset], got); + offset += got; + return got; + } + +/* +* Peek into a memory buffer +*/ +size_t DataSource_Memory::peek(byte out[], size_t length, + size_t peek_offset) const + { + const size_t bytes_left = source.size() - offset; + if(peek_offset >= bytes_left) return 0; + + size_t got = std::min(bytes_left - peek_offset, length); + copy_mem(out, &source[offset + peek_offset], got); + return got; + } + +/* +* Check if the memory buffer is empty +*/ +bool DataSource_Memory::end_of_data() const + { + return (offset == source.size()); + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const std::string& in) : + source(reinterpret_cast(in.data()), + reinterpret_cast(in.data()) + in.length()), + offset(0) + { + offset = 0; + } + +/* +* Read from a stream +*/ +size_t DataSource_Stream::read(byte out[], size_t length) + { + source.read(reinterpret_cast(out), length); + if(source.bad()) + throw Stream_IO_Error("DataSource_Stream::read: Source failure"); + + size_t got = source.gcount(); + total_read += got; + return got; + } + +/* +* Peek into a stream +*/ +size_t DataSource_Stream::peek(byte out[], size_t length, size_t offset) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); + + size_t got = 0; + + if(offset) + { + secure_vector buf(offset); + source.read(reinterpret_cast(&buf[0]), buf.size()); + if(source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = source.gcount(); + } + + if(got == offset) + { + source.read(reinterpret_cast(out), length); + if(source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = source.gcount(); + } + + if(source.eof()) + source.clear(); + source.seekg(total_read, std::ios::beg); + + return got; + } + +/* +* Check if the stream is empty or in error +*/ +bool DataSource_Stream::end_of_data() const + { + return (!source.good()); + } + +/* +* Return a human-readable ID for this stream +*/ +std::string DataSource_Stream::id() const + { + return identifier; + } + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(const std::string& path, + bool use_binary) : + identifier(path), + source_p(new std::ifstream( + path.c_str(), + use_binary ? std::ios::binary : std::ios::in)), + source(*source_p), + total_read(0) + { + if(!source.good()) + { + delete source_p; + throw Stream_IO_Error("DataSource: Failure opening file " + path); + } + } + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(std::istream& in, + const std::string& name) : + identifier(name), + source_p(nullptr), + source(in), + total_read(0) + { + } + +/* +* DataSource_Stream Destructor +*/ +DataSource_Stream::~DataSource_Stream() + { + delete source_p; + } + +} diff --git a/src/lib/filters/data_src.h b/src/lib/filters/data_src.h new file mode 100644 index 000000000..e28ef7be1 --- /dev/null +++ b/src/lib/filters/data_src.h @@ -0,0 +1,176 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DATA_SRC_H__ +#define BOTAN_DATA_SRC_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents an abstract data source object. +*/ +class BOTAN_DLL DataSource + { + public: + /** + * Read from the source. Moves the internal offset so that every + * call to read will return a new portion of the source. + * + * @param out the byte array to write the result to + * @param length the length of the byte array out + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t read(byte out[], size_t length) = 0; + + /** + * Read from the source but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the source starting at the same position. + * + * @param out the byte array to write the output to + * @param length the length of the byte array out + * @param peek_offset the offset into the stream to read at + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t peek(byte out[], size_t length, + size_t peek_offset) const = 0; + + /** + * Test whether the source still has data that can be read. + * @return true if there is still data to read, false otherwise + */ + virtual bool end_of_data() const = 0; + /** + * return the id of this data source + * @return std::string representing the id of this data source + */ + virtual std::string id() const { return ""; } + + /** + * Read one byte. + * @param out the byte to read to + * @return length in bytes that was actually read and put + * into out + */ + size_t read_byte(byte& out); + + /** + * Peek at one byte. + * @param out an output byte + * @return length in bytes that was actually read and put + * into out + */ + size_t peek_byte(byte& out) const; + + /** + * Discard the next N bytes of the data + * @param N the number of bytes to discard + * @return number of bytes actually discarded + */ + size_t discard_next(size_t N); + + /** + * @return number of bytes read so far. + */ + virtual size_t get_bytes_read() const = 0; + + DataSource() {} + virtual ~DataSource() {} + DataSource& operator=(const DataSource&) = delete; + DataSource(const DataSource&) = delete; + }; + +/** +* This class represents a Memory-Based DataSource +*/ +class BOTAN_DLL DataSource_Memory : public DataSource + { + public: + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t) const; + bool end_of_data() const; + + /** + * Construct a memory source that reads from a string + * @param in the string to read from + */ + DataSource_Memory(const std::string& in); + + /** + * Construct a memory source that reads from a byte array + * @param in the byte array to read from + * @param length the length of the byte array + */ + DataSource_Memory(const byte in[], size_t length) : + source(in, in + length), offset(0) {} + + /** + * Construct a memory source that reads from a secure_vector + * @param in the MemoryRegion to read from + */ + DataSource_Memory(const secure_vector& in) : + source(in), offset(0) {} + + /** + * Construct a memory source that reads from a std::vector + * @param in the MemoryRegion to read from + */ + DataSource_Memory(const std::vector& in) : + source(&in[0], &in[in.size()]), offset(0) {} + + virtual size_t get_bytes_read() const { return offset; } + private: + secure_vector source; + size_t offset; + }; + +/** +* This class represents a Stream-Based DataSource. +*/ +class BOTAN_DLL DataSource_Stream : public DataSource + { + public: + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t) const; + bool end_of_data() const; + std::string id() const; + + DataSource_Stream(std::istream&, + const std::string& id = ""); + + /** + * Construct a Stream-Based DataSource from file + * @param file the name of the file + * @param use_binary whether to treat the file as binary or not + */ + DataSource_Stream(const std::string& file, bool use_binary = false); + + DataSource_Stream(const DataSource_Stream&) = delete; + + DataSource_Stream& operator=(const DataSource_Stream&) = delete; + + ~DataSource_Stream(); + + virtual size_t get_bytes_read() const { return total_read; } + private: + const std::string identifier; + + std::istream* source_p; + std::istream& source; + size_t total_read; + }; + +} + +#endif diff --git a/src/lib/filters/fd_unix/fd_unix.cpp b/src/lib/filters/fd_unix/fd_unix.cpp new file mode 100644 index 000000000..dc6fbe696 --- /dev/null +++ b/src/lib/filters/fd_unix/fd_unix.cpp @@ -0,0 +1,53 @@ +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Write data from a pipe into a Unix fd +*/ +int operator<<(int fd, Pipe& pipe) + { + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + size_t got = pipe.read(&buffer[0], buffer.size()); + size_t position = 0; + while(got) + { + ssize_t ret = write(fd, &buffer[position], got); + if(ret == -1) + throw Stream_IO_Error("Pipe output operator (unixfd) has failed"); + position += ret; + got -= ret; + } + } + return fd; + } + +/* +* Read data from a Unix fd into a pipe +*/ +int operator>>(int fd, Pipe& pipe) + { + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(true) + { + ssize_t ret = read(fd, &buffer[0], buffer.size()); + if(ret == 0) break; + if(ret == -1) + throw Stream_IO_Error("Pipe input operator (unixfd) has failed"); + pipe.write(&buffer[0], ret); + } + return fd; + } + +} diff --git a/src/lib/filters/fd_unix/fd_unix.h b/src/lib/filters/fd_unix/fd_unix.h new file mode 100644 index 000000000..8335aed9e --- /dev/null +++ b/src/lib/filters/fd_unix/fd_unix.h @@ -0,0 +1,33 @@ +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PIPE_UNIXFD_H__ +#define BOTAN_PIPE_UNIXFD_H__ + +#include + +namespace Botan { + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out file descriptor for an open output stream +* @param pipe the pipe +*/ +int BOTAN_DLL operator<<(int out, Pipe& pipe); + +/** +* File descriptor input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in file descriptor for an open input stream +* @param pipe the pipe +*/ +int BOTAN_DLL operator>>(int in, Pipe& pipe); + +} + +#endif diff --git a/src/lib/filters/fd_unix/info.txt b/src/lib/filters/fd_unix/info.txt new file mode 100644 index 000000000..271b7919e --- /dev/null +++ b/src/lib/filters/fd_unix/info.txt @@ -0,0 +1,20 @@ +define PIPE_UNIXFD_IO 20131128 + +load_on auto + + +aix +cygwin +darwin +dragonfly +freebsd +haiku +hpux +irix +linux +netbsd +openbsd +qnx +solaris +tru64 + diff --git a/src/lib/filters/filter.cpp b/src/lib/filters/filter.cpp new file mode 100644 index 000000000..3eb924172 --- /dev/null +++ b/src/lib/filters/filter.cpp @@ -0,0 +1,127 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Filter Constructor +*/ +Filter::Filter() + { + next.resize(1); + port_num = 0; + filter_owns = 0; + owned = false; + } + +/* +* Send data to all ports +*/ +void Filter::send(const byte input[], size_t length) + { + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + { + if(write_queue.size()) + next[j]->write(&write_queue[0], write_queue.size()); + next[j]->write(input, length); + nothing_attached = false; + } + + if(nothing_attached) + write_queue += std::make_pair(input, length); + else + write_queue.clear(); + } + +/* +* Start a new message +*/ +void Filter::new_msg() + { + start_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + next[j]->new_msg(); + } + +/* +* End the current message +*/ +void Filter::finish_msg() + { + end_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + next[j]->finish_msg(); + } + +/* +* Attach a filter to the current port +*/ +void Filter::attach(Filter* new_filter) + { + if(new_filter) + { + Filter* last = this; + while(last->get_next()) + last = last->get_next(); + last->next[last->current_port()] = new_filter; + } + } + +/* +* Set the active port on a filter +*/ +void Filter::set_port(size_t new_port) + { + if(new_port >= total_ports()) + throw Invalid_Argument("Filter: Invalid port number"); + port_num = new_port; + } + +/* +* Return the next Filter in the logical chain +*/ +Filter* Filter::get_next() const + { + if(port_num < next.size()) + return next[port_num]; + return nullptr; + } + +/* +* Set the next Filters +*/ +void Filter::set_next(Filter* filters[], size_t size) + { + next.clear(); + + port_num = 0; + filter_owns = 0; + + while(size && filters && (filters[size-1] == nullptr)) + --size; + + if(filters && size) + next.assign(filters, filters + size); + } + +/* +* Return the total number of ports +*/ +size_t Filter::total_ports() const + { + return next.size(); + } + +} diff --git a/src/lib/filters/filter.h b/src/lib/filters/filter.h new file mode 100644 index 000000000..bdf4d11a4 --- /dev/null +++ b/src/lib/filters/filter.h @@ -0,0 +1,183 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* (C) 2013 Joel Low +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_FILTER_H__ +#define BOTAN_FILTER_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents general abstract filter objects. +*/ +class BOTAN_DLL Filter + { + public: + /** + * @return descriptive name for this filter + */ + virtual std::string name() const = 0; + + /** + * Write a portion of a message to this filter. + * @param input the input as a byte array + * @param length the length of the byte array input + */ + virtual void write(const byte input[], size_t length) = 0; + + /** + * Start a new message. Must be closed by end_msg() before another + * message can be started. + */ + virtual void start_msg() {} + + /** + * Notify that the current message is finished; flush buffers and + * do end-of-message processing (if any). + */ + virtual void end_msg() {} + + /** + * Check whether this filter is an attachable filter. + * @return true if this filter is attachable, false otherwise + */ + virtual bool attachable() { return true; } + + virtual ~Filter() {} + protected: + /** + * @param in some input for the filter + * @param length the length of in + */ + virtual void send(const byte in[], size_t length); + + /** + * @param in some input for the filter + */ + void send(byte in) { send(&in, 1); } + + /** + * @param in some input for the filter + */ + void send(const secure_vector& in) { send(&in[0], in.size()); } + + /** + * @param in some input for the filter + */ + void send(const std::vector& in) { send(&in[0], in.size()); } + + /** + * @param in some input for the filter + * @param length the number of bytes of in to send + */ + void send(const secure_vector& in, size_t length) + { + send(&in[0], length); + } + + /** + * @param in some input for the filter + * @param length the number of bytes of in to send + */ + void send(const std::vector& in, size_t length) + { + send(&in[0], length); + } + + Filter(); + + Filter(const Filter&) = delete; + + Filter& operator=(const Filter&) = delete; + + private: + /** + * Start a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void new_msg(); + + /** + * End a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void finish_msg(); + + friend class Pipe; + friend class Fanout_Filter; + + size_t total_ports() const; + size_t current_port() const { return port_num; } + + /** + * Set the active port + * @param new_port the new value + */ + void set_port(size_t new_port); + + size_t owns() const { return filter_owns; } + + /** + * Attach another filter to this one + * @param f filter to attach + */ + void attach(Filter* f); + + /** + * @param filters the filters to set + * @param count number of items in filters + */ + void set_next(Filter* filters[], size_t count); + Filter* get_next() const; + + secure_vector write_queue; + std::vector next; + size_t port_num, filter_owns; + + // true if filter belongs to a pipe --> prohibit filter sharing! + bool owned; + }; + +/** +* This is the abstract Fanout_Filter base class. +**/ +class BOTAN_DLL Fanout_Filter : public Filter + { + protected: + /** + * Increment the number of filters past us that we own + */ + void incr_owns() { ++filter_owns; } + + void set_port(size_t n) { Filter::set_port(n); } + + void set_next(Filter* f[], size_t n) { Filter::set_next(f, n); } + + void attach(Filter* f) { Filter::attach(f); } + + private: + friend class Threaded_Fork; + using Filter::write_queue; + using Filter::total_ports; + using Filter::next; + }; + +/** +* The type of checking to be performed by decoders: +* NONE - no checks, IGNORE_WS - perform checks, but ignore +* whitespaces, FULL_CHECK - perform checks, also complain +* about white spaces. +*/ +enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK }; + +} + +#endif diff --git a/src/lib/filters/filters.h b/src/lib/filters/filters.h new file mode 100644 index 000000000..5973cbf50 --- /dev/null +++ b/src/lib/filters/filters.h @@ -0,0 +1,213 @@ +/* +* Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_FILTERS_H__ +#define BOTAN_FILTERS_H__ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#if defined(BOTAN_HAS_CODEC_FILTERS) + #include + #include +#endif + +namespace Botan { + +/** +* Stream Cipher Filter +*/ +class BOTAN_DLL StreamCipher_Filter : public Keyed_Filter + { + public: + + std::string name() const { return cipher->name(); } + + /** + * Write input data + * @param input data + * @param input_len length of input in bytes + */ + void write(const byte input[], size_t input_len); + + bool valid_iv_length(size_t iv_len) const + { return cipher->valid_iv_length(iv_len); } + + /** + * Set the initialization vector for this filter. + * @param iv the initialization vector to set + */ + void set_iv(const InitializationVector& iv); + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + Key_Length_Specification key_spec() const override { return cipher->key_spec(); } + + /** + * Construct a stream cipher filter. + * @param cipher_obj a cipher object to use + */ + StreamCipher_Filter(StreamCipher* cipher_obj); + + /** + * Construct a stream cipher filter. + * @param cipher_obj a cipher object to use + * @param key the key to use inside this filter + */ + StreamCipher_Filter(StreamCipher* cipher_obj, const SymmetricKey& key); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + */ + StreamCipher_Filter(const std::string& cipher); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + * @param key the key to use inside this filter + */ + StreamCipher_Filter(const std::string& cipher, const SymmetricKey& key); + + ~StreamCipher_Filter() { delete cipher; } + private: + secure_vector buffer; + StreamCipher* cipher; + }; + +/** +* Hash Filter. +*/ +class BOTAN_DLL Hash_Filter : public Filter + { + public: + void write(const byte input[], size_t len) { hash->update(input, len); } + void end_msg(); + + std::string name() const { return hash->name(); } + + /** + * Construct a hash filter. + * @param hash_fun the hash function to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(HashFunction* hash_fun, size_t len = 0) : + OUTPUT_LENGTH(len), hash(hash_fun) {} + + /** + * Construct a hash filter. + * @param request the name of the hash algorithm to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(const std::string& request, size_t len = 0); + + ~Hash_Filter() { delete hash; } + private: + const size_t OUTPUT_LENGTH; + HashFunction* hash; + }; + +/** +* MessageAuthenticationCode Filter. +*/ +class BOTAN_DLL MAC_Filter : public Keyed_Filter + { + public: + void write(const byte input[], size_t len) { mac->update(input, len); } + void end_msg(); + + std::string name() const { return mac->name(); } + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) { mac->set_key(key); } + + Key_Length_Specification key_spec() const override { return mac->key_spec(); } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac_obj the MAC to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac_obj, + size_t out_len = 0) : OUTPUT_LENGTH(out_len) + { + mac = mac_obj; + } + + /** + * Construct a MAC filter. + * @param mac_obj the MAC to use + * @param key the MAC key to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac_obj, + const SymmetricKey& key, + size_t out_len = 0) : OUTPUT_LENGTH(out_len) + { + mac = mac_obj; + mac->set_key(key); + } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the name of the MAC to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, size_t len = 0); + + /** + * Construct a MAC filter. + * @param mac the name of the MAC to use + * @param key the MAC key to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, const SymmetricKey& key, + size_t len = 0); + + ~MAC_Filter() { delete mac; } + private: + const size_t OUTPUT_LENGTH; + MessageAuthenticationCode* mac; + }; + +} + +#endif diff --git a/src/lib/filters/info.txt b/src/lib/filters/info.txt new file mode 100644 index 000000000..4145af34a --- /dev/null +++ b/src/lib/filters/info.txt @@ -0,0 +1,46 @@ +define FILTERS 20131128 + + +algo_filt.cpp +basefilt.cpp +buf_filt.cpp +data_snk.cpp +data_src.cpp +filter.cpp +out_buf.cpp +pipe.cpp +pipe_io.cpp +pipe_rw.cpp +secqueue.cpp +threaded_fork.cpp +transform_filter.cpp + + + +basefilt.h +buf_filt.h +data_snk.h +data_src.h +filter.h +filters.h +key_filt.h +pipe.h +secqueue.h +transform_filter.h + + + +out_buf.h + + + +alloc +asn1 +block +hash +libstate +mac +rng +stream +algo_base + diff --git a/src/lib/filters/key_filt.h b/src/lib/filters/key_filt.h new file mode 100644 index 000000000..6d69d6b83 --- /dev/null +++ b/src/lib/filters/key_filt.h @@ -0,0 +1,62 @@ +/* +* Keyed_Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KEYED_FILTER_H__ +#define BOTAN_KEYED_FILTER_H__ + +#include +#include + +namespace Botan { + +/** +* This class represents keyed filters, i.e. filters that have to be +* fed with a key in order to function. +*/ +class BOTAN_DLL Keyed_Filter : public Filter + { + public: + /** + * Set the key of this filter + * @param key the key to use + */ + virtual void set_key(const SymmetricKey& key) = 0; + + /** + * Set the initialization vector of this filter. Note: you should + * call set_iv() only after you have called set_key() + * @param iv the initialization vector to use + */ + virtual void set_iv(const InitializationVector& iv); + + /** + * Check whether a key length is valid for this filter + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * Check whether an IV length is valid for this filter + * @param length the IV length to be checked for validity + * @return true if the IV length is valid, false otherwise + */ + virtual bool valid_iv_length(size_t length) const + { return (length == 0); } + }; + +} + +#endif diff --git a/src/lib/filters/out_buf.cpp b/src/lib/filters/out_buf.cpp new file mode 100644 index 000000000..323b20e1d --- /dev/null +++ b/src/lib/filters/out_buf.cpp @@ -0,0 +1,131 @@ +/* +* Pipe Output Buffer +* (C) 1999-2007,2011 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Read data from a message +*/ +size_t Output_Buffers::read(byte output[], size_t length, + Pipe::message_id msg) + { + SecureQueue* q = get(msg); + if(q) + return q->read(output, length); + return 0; + } + +/* +* Peek at data in a message +*/ +size_t Output_Buffers::peek(byte output[], size_t length, + size_t stream_offset, + Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->peek(output, length, stream_offset); + return 0; + } + +/* +* Check available bytes in a message +*/ +size_t Output_Buffers::remaining(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->size(); + return 0; + } + +/* +* Return the total bytes of a message that have already been read. +*/ +size_t Output_Buffers::get_bytes_read(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if (q) + return q->get_bytes_read(); + return 0; + } + +/* +* Add a new output queue +*/ +void Output_Buffers::add(SecureQueue* queue) + { + BOTAN_ASSERT(queue, "queue was provided"); + + BOTAN_ASSERT(buffers.size() < buffers.max_size(), + "Room was available in container"); + + buffers.push_back(queue); + } + +/* +* Retire old output queues +*/ +void Output_Buffers::retire() + { + for(size_t i = 0; i != buffers.size(); ++i) + if(buffers[i] && buffers[i]->size() == 0) + { + delete buffers[i]; + buffers[i] = nullptr; + } + + while(buffers.size() && !buffers[0]) + { + buffers.pop_front(); + offset = offset + Pipe::message_id(1); + } + } + +/* +* Get a particular output queue +*/ +SecureQueue* Output_Buffers::get(Pipe::message_id msg) const + { + if(msg < offset) + return nullptr; + + BOTAN_ASSERT(msg < message_count(), "Message number is in range"); + + return buffers[msg-offset]; + } + +/* +* Return the total number of messages +*/ +Pipe::message_id Output_Buffers::message_count() const + { + return (offset + buffers.size()); + } + +/* +* Output_Buffers Constructor +*/ +Output_Buffers::Output_Buffers() + { + offset = 0; + } + +/* +* Output_Buffers Destructor +*/ +Output_Buffers::~Output_Buffers() + { + for(size_t j = 0; j != buffers.size(); ++j) + delete buffers[j]; + } + +} diff --git a/src/lib/filters/out_buf.h b/src/lib/filters/out_buf.h new file mode 100644 index 000000000..2d17ac8d3 --- /dev/null +++ b/src/lib/filters/out_buf.h @@ -0,0 +1,45 @@ +/* +* Output Buffer +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OUTPUT_BUFFER_H__ +#define BOTAN_OUTPUT_BUFFER_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Container of output buffers for Pipe +*/ +class Output_Buffers + { + public: + size_t read(byte[], size_t, Pipe::message_id); + size_t peek(byte[], size_t, size_t, Pipe::message_id) const; + size_t get_bytes_read(Pipe::message_id) const; + size_t remaining(Pipe::message_id) const; + + void add(class SecureQueue*); + void retire(); + + Pipe::message_id message_count() const; + + Output_Buffers(); + ~Output_Buffers(); + private: + class SecureQueue* get(Pipe::message_id) const; + + std::deque buffers; + Pipe::message_id offset; + }; + +} + +#endif diff --git a/src/lib/filters/pipe.cpp b/src/lib/filters/pipe.cpp new file mode 100644 index 000000000..e3c2f53b6 --- /dev/null +++ b/src/lib/filters/pipe.cpp @@ -0,0 +1,302 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* A Filter that does nothing +*/ +class Null_Filter : public Filter + { + public: + void write(const byte input[], size_t length) + { send(input, length); } + + std::string name() const { return "Null"; } + }; + +} + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + init(); + append(f1); + append(f2); + append(f3); + append(f4); + } + +/* +* Pipe Constructor +*/ +Pipe::Pipe(std::initializer_list args) + { + init(); + + for(auto i = args.begin(); i != args.end(); ++i) + append(*i); + } + +/* +* Pipe Destructor +*/ +Pipe::~Pipe() + { + destruct(pipe); + delete outputs; + } + +/* +* Initialize the Pipe +*/ +void Pipe::init() + { + outputs = new Output_Buffers; + pipe = nullptr; + default_read = 0; + inside_msg = false; + } + +/* +* Reset the Pipe +*/ +void Pipe::reset() + { + destruct(pipe); + pipe = nullptr; + inside_msg = false; + } + +/* +* Destroy the Pipe +*/ +void Pipe::destruct(Filter* to_kill) + { + if(!to_kill || dynamic_cast(to_kill)) + return; + for(size_t j = 0; j != to_kill->total_ports(); ++j) + destruct(to_kill->next[j]); + delete to_kill; + } + +/* +* Test if the Pipe has any data in it +*/ +bool Pipe::end_of_data() const + { + return (remaining() == 0); + } + +/* +* Set the default read message +*/ +void Pipe::set_default_msg(message_id msg) + { + if(msg >= message_count()) + throw Invalid_Argument("Pipe::set_default_msg: msg number is too high"); + default_read = msg; + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const byte input[], size_t length) + { + start_msg(); + write(input, length); + end_msg(); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const secure_vector& input) + { + process_msg(&input[0], input.size()); + } + +void Pipe::process_msg(const std::vector& input) + { + process_msg(&input[0], input.size()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const std::string& input) + { + process_msg(reinterpret_cast(input.data()), input.length()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(DataSource& input) + { + start_msg(); + write(input); + end_msg(); + } + +/* +* Start a new message +*/ +void Pipe::start_msg() + { + if(inside_msg) + throw Invalid_State("Pipe::start_msg: Message was already started"); + if(pipe == nullptr) + pipe = new Null_Filter; + find_endpoints(pipe); + pipe->new_msg(); + inside_msg = true; + } + +/* +* End the current message +*/ +void Pipe::end_msg() + { + if(!inside_msg) + throw Invalid_State("Pipe::end_msg: Message was already ended"); + pipe->finish_msg(); + clear_endpoints(pipe); + if(dynamic_cast(pipe)) + { + delete pipe; + pipe = nullptr; + } + inside_msg = false; + + outputs->retire(); + } + +/* +* Find the endpoints of the Pipe +*/ +void Pipe::find_endpoints(Filter* f) + { + for(size_t j = 0; j != f->total_ports(); ++j) + if(f->next[j] && !dynamic_cast(f->next[j])) + find_endpoints(f->next[j]); + else + { + SecureQueue* q = new SecureQueue; + f->next[j] = q; + outputs->add(q); + } + } + +/* +* Remove the SecureQueues attached to the Filter +*/ +void Pipe::clear_endpoints(Filter* f) + { + if(!f) return; + for(size_t j = 0; j != f->total_ports(); ++j) + { + if(f->next[j] && dynamic_cast(f->next[j])) + f->next[j] = nullptr; + clear_endpoints(f->next[j]); + } + } + +/* +* Append a Filter to the Pipe +*/ +void Pipe::append(Filter* filter) + { + if(inside_msg) + throw Invalid_State("Cannot append to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); + if(filter->owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->owned = true; + + if(!pipe) pipe = filter; + else pipe->attach(filter); + } + +/* +* Prepend a Filter to the Pipe +*/ +void Pipe::prepend(Filter* filter) + { + if(inside_msg) + throw Invalid_State("Cannot prepend to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); + if(filter->owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->owned = true; + + if(pipe) filter->attach(pipe); + pipe = filter; + } + +/* +* Pop a Filter off the Pipe +*/ +void Pipe::pop() + { + if(inside_msg) + throw Invalid_State("Cannot pop off a Pipe while it is processing"); + + if(!pipe) + return; + + if(pipe->total_ports() > 1) + throw Invalid_State("Cannot pop off a Filter with multiple ports"); + + Filter* f = pipe; + size_t owns = f->owns(); + pipe = pipe->next[0]; + delete f; + + while(owns--) + { + f = pipe; + pipe = pipe->next[0]; + delete f; + } + } + +/* +* Return the number of messages in this Pipe +*/ +Pipe::message_id Pipe::message_count() const + { + return outputs->message_count(); + } + +/* +* Static Member Variables +*/ +const Pipe::message_id Pipe::LAST_MESSAGE = + static_cast(-2); + +const Pipe::message_id Pipe::DEFAULT_MESSAGE = + static_cast(-1); + +} diff --git a/src/lib/filters/pipe.h b/src/lib/filters/pipe.h new file mode 100644 index 000000000..ec56d4503 --- /dev/null +++ b/src/lib/filters/pipe.h @@ -0,0 +1,339 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PIPE_H__ +#define BOTAN_PIPE_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents pipe objects. +* A set of filters can be placed into a pipe, and information flows +* through the pipe until it reaches the end, where the output is +* collected for retrieval. If you're familiar with the Unix shell +* environment, this design will sound quite familiar. +*/ +class BOTAN_DLL Pipe : public DataSource + { + public: + /** + * An opaque type that identifies a message in this Pipe + */ + typedef size_t message_id; + + /** + * Exception if you use an invalid message as an argument to + * read, remaining, etc + */ + struct BOTAN_DLL Invalid_Message_Number : public Invalid_Argument + { + /** + * @param where the error occured + * @param msg the invalid message id that was used + */ + Invalid_Message_Number(const std::string& where, message_id msg) : + Invalid_Argument("Pipe::" + where + ": Invalid message number " + + std::to_string(msg)) + {} + }; + + /** + * A meta-id for whatever the last message is + */ + static const message_id LAST_MESSAGE; + + /** + * A meta-id for the default message (set with set_default_msg) + */ + static const message_id DEFAULT_MESSAGE; + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the byte array to write + * @param length the length of the byte array in + */ + void write(const byte in[], size_t length); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the secure_vector containing the data to write + */ + void write(const secure_vector& in) + { write(&in[0], in.size()); } + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the std::vector containing the data to write + */ + void write(const std::vector& in) + { write(&in[0], in.size()); } + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the string containing the data to write + */ + void write(const std::string& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the DataSource to read the data from + */ + void write(DataSource& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in a single byte to be written + */ + void write(byte in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the byte array containing the data to write + * @param length the length of the byte array to write + */ + void process_msg(const byte in[], size_t length); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the secure_vector containing the data to write + */ + void process_msg(const secure_vector& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the secure_vector containing the data to write + */ + void process_msg(const std::vector& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the string containing the data to write + */ + void process_msg(const std::string& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the DataSource providing the data to write + */ + void process_msg(DataSource& in); + + /** + * Find out how many bytes are ready to read. + * @param msg the number identifying the message + * for which the information is desired + * @return number of bytes that can still be read + */ + size_t remaining(message_id msg = DEFAULT_MESSAGE) const; + + /** + * Read the default message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @return number of bytes actually read into output + */ + size_t read(byte output[], size_t length); + + /** + * Read a specified message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @param msg the number identifying the message to read from + * @return number of bytes actually read into output + */ + size_t read(byte output[], size_t length, message_id msg); + + /** + * Read a single byte from the pipe. Moves the internal offset so + * that every call to read will return a new portion of the + * message. + * + * @param output the byte to write the result to + * @param msg the message to read from + * @return number of bytes actually read into output + */ + size_t read(byte& output, message_id msg = DEFAULT_MESSAGE); + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return secure_vector holding the contents of the pipe + */ + secure_vector read_all(message_id msg = DEFAULT_MESSAGE); + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return string holding the contents of the pipe + */ + std::string read_all_as_string(message_id = DEFAULT_MESSAGE); + + /** Read from the default message but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @return number of bytes actually peeked and written into output + */ + size_t peek(byte output[], size_t length, size_t offset) const; + + /** Read from the specified message but do not modify the + * internal offset. Consecutive calls to peek() will return + * portions of the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(byte output[], size_t length, + size_t offset, message_id msg) const; + + /** Read a single byte from the specified message but do not + * modify the internal offset. Consecutive calls to peek() will + * return portions of the message starting at the same position. + * @param output the byte to write the peeked message byte to + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(byte& output, size_t offset, + message_id msg = DEFAULT_MESSAGE) const; + + /** + * @return the number of bytes read from the default message. + */ + size_t get_bytes_read() const; + + /** + * @return the number of bytes read from the specified message. + */ + size_t get_bytes_read(message_id msg = DEFAULT_MESSAGE) const; + + /** + * @return currently set default message + */ + size_t default_msg() const { return default_read; } + + /** + * Set the default message + * @param msg the number identifying the message which is going to + * be the new default message + */ + void set_default_msg(message_id msg); + + /** + * Get the number of messages the are in this pipe. + * @return number of messages the are in this pipe + */ + message_id message_count() const; + + /** + * Test whether this pipe has any data that can be read from. + * @return true if there is more data to read, false otherwise + */ + bool end_of_data() const; + + /** + * Start a new message in the pipe. A potential other message in this pipe + * must be closed with end_msg() before this function may be called. + */ + void start_msg(); + + /** + * End the current message. + */ + void end_msg(); + + /** + * Insert a new filter at the front of the pipe + * @param filt the new filter to insert + */ + void prepend(Filter* filt); + + /** + * Insert a new filter at the back of the pipe + * @param filt the new filter to insert + */ + void append(Filter* filt); + + /** + * Remove the first filter at the front of the pipe. + */ + void pop(); + + /** + * Reset this pipe to an empty pipe. + */ + void reset(); + + /** + * Construct a Pipe of up to four filters. The filters are set up + * in the same order as the arguments. + */ + Pipe(Filter* = nullptr, Filter* = nullptr, + Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Pipe from a list of filters + * @param filters the set of filters to use + */ + Pipe(std::initializer_list filters); + + Pipe(const Pipe&) = delete; + Pipe& operator=(const Pipe&) = delete; + + ~Pipe(); + private: + void init(); + void destruct(Filter*); + void find_endpoints(Filter*); + void clear_endpoints(Filter*); + + message_id get_message_no(const std::string&, message_id) const; + + Filter* pipe; + class Output_Buffers* outputs; + message_id default_read; + bool inside_msg; + }; + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out an output stream +* @param pipe the pipe +*/ +BOTAN_DLL std::ostream& operator<<(std::ostream& out, Pipe& pipe); + +/** +* Stream input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in the input stream +* @param pipe the pipe +*/ +BOTAN_DLL std::istream& operator>>(std::istream& in, Pipe& pipe); + +} + +#if defined(BOTAN_HAS_PIPE_UNIXFD_IO) + #include +#endif + +#endif diff --git a/src/lib/filters/pipe_io.cpp b/src/lib/filters/pipe_io.cpp new file mode 100644 index 000000000..a549eaee8 --- /dev/null +++ b/src/lib/filters/pipe_io.cpp @@ -0,0 +1,45 @@ +/* +* Pipe I/O +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Write data from a pipe into an ostream +*/ +std::ostream& operator<<(std::ostream& stream, Pipe& pipe) + { + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(stream.good() && pipe.remaining()) + { + size_t got = pipe.read(&buffer[0], buffer.size()); + stream.write(reinterpret_cast(&buffer[0]), got); + } + if(!stream.good()) + throw Stream_IO_Error("Pipe output operator (iostream) has failed"); + return stream; + } + +/* +* Read data from an istream into a pipe +*/ +std::istream& operator>>(std::istream& stream, Pipe& pipe) + { + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(stream.good()) + { + stream.read(reinterpret_cast(&buffer[0]), buffer.size()); + pipe.write(&buffer[0], stream.gcount()); + } + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("Pipe input operator (iostream) has failed"); + return stream; + } + +} diff --git a/src/lib/filters/pipe_rw.cpp b/src/lib/filters/pipe_rw.cpp new file mode 100644 index 000000000..06b87406e --- /dev/null +++ b/src/lib/filters/pipe_rw.cpp @@ -0,0 +1,171 @@ +/* +* Pipe Reading/Writing +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Look up the canonical ID for a queue +*/ +Pipe::message_id Pipe::get_message_no(const std::string& func_name, + message_id msg) const + { + if(msg == DEFAULT_MESSAGE) + msg = default_msg(); + else if(msg == LAST_MESSAGE) + msg = message_count() - 1; + + if(msg >= message_count()) + throw Invalid_Message_Number(func_name, msg); + + return msg; + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const byte input[], size_t length) + { + if(!inside_msg) + throw Invalid_State("Cannot write to a Pipe while it is not processing"); + pipe->write(input, length); + } + +/* +* Write a string into a Pipe +*/ +void Pipe::write(const std::string& str) + { + write(reinterpret_cast(str.data()), str.size()); + } + +/* +* Write a single byte into a Pipe +*/ +void Pipe::write(byte input) + { + write(&input, 1); + } + +/* +* Write the contents of a DataSource into a Pipe +*/ +void Pipe::write(DataSource& source) + { + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(!source.end_of_data()) + { + size_t got = source.read(&buffer[0], buffer.size()); + write(&buffer[0], got); + } + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(byte output[], size_t length, message_id msg) + { + return outputs->read(output, length, get_message_no("read", msg)); + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(byte output[], size_t length) + { + return read(output, length, DEFAULT_MESSAGE); + } + +/* +* Read a single byte from the pipe +*/ +size_t Pipe::read(byte& out, message_id msg) + { + return read(&out, 1, msg); + } + +/* +* Return all data in the pipe +*/ +secure_vector Pipe::read_all(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + secure_vector buffer(remaining(msg)); + size_t got = read(&buffer[0], buffer.size(), msg); + buffer.resize(got); + return buffer; + } + +/* +* Return all data in the pipe as a string +*/ +std::string Pipe::read_all_as_string(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + secure_vector buffer(DEFAULT_BUFFERSIZE); + std::string str; + str.reserve(remaining(msg)); + + while(true) + { + size_t got = read(&buffer[0], buffer.size(), msg); + if(got == 0) + break; + str.append(reinterpret_cast(&buffer[0]), got); + } + + return str; + } + +/* +* Find out how many bytes are ready to read +*/ +size_t Pipe::remaining(message_id msg) const + { + return outputs->remaining(get_message_no("remaining", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(byte output[], size_t length, + size_t offset, message_id msg) const + { + return outputs->peek(output, length, offset, get_message_no("peek", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(byte output[], size_t length, size_t offset) const + { + return peek(output, length, offset, DEFAULT_MESSAGE); + } + +/* +* Peek at a byte in the pipe +*/ +size_t Pipe::peek(byte& out, size_t offset, message_id msg) const + { + return peek(&out, 1, offset, msg); + } + +size_t Pipe::get_bytes_read() const + { + return outputs->get_bytes_read(DEFAULT_MESSAGE); + } + +size_t Pipe::get_bytes_read(message_id msg) const + { + return outputs->get_bytes_read(msg); + } + +} diff --git a/src/lib/filters/pk_filts/info.txt b/src/lib/filters/pk_filts/info.txt new file mode 100644 index 000000000..688075145 --- /dev/null +++ b/src/lib/filters/pk_filts/info.txt @@ -0,0 +1,8 @@ +define PUBLIC_KEY_CRYPTO 20131128 + +load_on auto + + +pubkey +filters + diff --git a/src/lib/filters/pk_filts/pk_filts.cpp b/src/lib/filters/pk_filts/pk_filts.cpp new file mode 100644 index 000000000..45fcc18b8 --- /dev/null +++ b/src/lib/filters/pk_filts/pk_filts.cpp @@ -0,0 +1,115 @@ +/* +* PK Filters +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Append to the buffer +*/ +void PK_Encryptor_Filter::write(const byte input[], size_t length) + { + buffer += std::make_pair(input, length); + } + +/* +* Encrypt the message +*/ +void PK_Encryptor_Filter::end_msg() + { + send(cipher->encrypt(buffer, rng)); + buffer.clear(); + } + +/* +* Append to the buffer +*/ +void PK_Decryptor_Filter::write(const byte input[], size_t length) + { + buffer += std::make_pair(input, length); + } + +/* +* Decrypt the message +*/ +void PK_Decryptor_Filter::end_msg() + { + send(cipher->decrypt(buffer)); + buffer.clear(); + } + +/* +* Add more data +*/ +void PK_Signer_Filter::write(const byte input[], size_t length) + { + signer->update(input, length); + } + +/* +* Sign the message +*/ +void PK_Signer_Filter::end_msg() + { + send(signer->signature(rng)); + } + +/* +* Add more data +*/ +void PK_Verifier_Filter::write(const byte input[], size_t length) + { + verifier->update(input, length); + } + +/* +* Verify the message +*/ +void PK_Verifier_Filter::end_msg() + { + if(signature.empty()) + throw Invalid_State("PK_Verifier_Filter: No signature to check against"); + bool is_valid = verifier->check_signature(signature); + send((is_valid ? 1 : 0)); + } + +/* +* Set the signature to check +*/ +void PK_Verifier_Filter::set_signature(const byte sig[], size_t length) + { + signature.assign(sig, sig + length); + } + +/* +* Set the signature to check +*/ +void PK_Verifier_Filter::set_signature(const secure_vector& sig) + { + signature = sig; + } + +/* +* PK_Verifier_Filter Constructor +*/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, const byte sig[], + size_t length) : + verifier(v), signature(sig, sig + length) + { + } + +/* +* PK_Verifier_Filter Constructor +*/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, + const secure_vector& sig) : + verifier(v), signature(sig) + { + } + +} diff --git a/src/lib/filters/pk_filts/pk_filts.h b/src/lib/filters/pk_filts/pk_filts.h new file mode 100644 index 000000000..cc1c2220d --- /dev/null +++ b/src/lib/filters/pk_filts/pk_filts.h @@ -0,0 +1,91 @@ +/* +* PK Filters +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_FILTERS_H__ +#define BOTAN_PK_FILTERS_H__ + +#include +#include + +namespace Botan { + +/** +* PK_Encryptor Filter +*/ +class BOTAN_DLL PK_Encryptor_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + PK_Encryptor_Filter(PK_Encryptor* c, + RandomNumberGenerator& rng_ref) : + cipher(c), rng(rng_ref) {} + ~PK_Encryptor_Filter() { delete cipher; } + private: + PK_Encryptor* cipher; + RandomNumberGenerator& rng; + secure_vector buffer; + }; + +/** +* PK_Decryptor Filter +*/ +class BOTAN_DLL PK_Decryptor_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + PK_Decryptor_Filter(PK_Decryptor* c) : cipher(c) {} + ~PK_Decryptor_Filter() { delete cipher; } + private: + PK_Decryptor* cipher; + secure_vector buffer; + }; + +/** +* PK_Signer Filter +*/ +class BOTAN_DLL PK_Signer_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + + PK_Signer_Filter(PK_Signer* s, + RandomNumberGenerator& rng_ref) : + signer(s), rng(rng_ref) {} + + ~PK_Signer_Filter() { delete signer; } + private: + PK_Signer* signer; + RandomNumberGenerator& rng; + }; + +/** +* PK_Verifier Filter +*/ +class BOTAN_DLL PK_Verifier_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + + void set_signature(const byte[], size_t); + void set_signature(const secure_vector&); + + PK_Verifier_Filter(PK_Verifier* v) : verifier(v) {} + PK_Verifier_Filter(PK_Verifier*, const byte[], size_t); + PK_Verifier_Filter(PK_Verifier*, const secure_vector&); + ~PK_Verifier_Filter() { delete verifier; } + private: + PK_Verifier* verifier; + secure_vector signature; + }; + +} + +#endif diff --git a/src/lib/filters/secqueue.cpp b/src/lib/filters/secqueue.cpp new file mode 100644 index 000000000..9908a2a8c --- /dev/null +++ b/src/lib/filters/secqueue.cpp @@ -0,0 +1,228 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/** +* A node in a SecureQueue +*/ +class SecureQueueNode + { + public: + SecureQueueNode() : buffer(DEFAULT_BUFFERSIZE) + { next = nullptr; start = end = 0; } + + ~SecureQueueNode() { next = nullptr; start = end = 0; } + + size_t write(const byte input[], size_t length) + { + size_t copied = std::min(length, buffer.size() - end); + copy_mem(&buffer[end], input, copied); + end += copied; + return copied; + } + + size_t read(byte output[], size_t length) + { + size_t copied = std::min(length, end - start); + copy_mem(output, &buffer[start], copied); + start += copied; + return copied; + } + + size_t peek(byte output[], size_t length, size_t offset = 0) + { + const size_t left = end - start; + if(offset >= left) return 0; + size_t copied = std::min(length, left - offset); + copy_mem(output, &buffer[start + offset], copied); + return copied; + } + + size_t size() const { return (end - start); } + private: + friend class SecureQueue; + SecureQueueNode* next; + secure_vector buffer; + size_t start, end; + }; + +/* +* Create a SecureQueue +*/ +SecureQueue::SecureQueue() + { + bytes_read = 0; + set_next(nullptr, 0); + head = tail = new SecureQueueNode; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue::SecureQueue(const SecureQueue& input) : + Fanout_Filter(), DataSource() + { + bytes_read = 0; + set_next(nullptr, 0); + + head = tail = new SecureQueueNode; + SecureQueueNode* temp = input.head; + while(temp) + { + write(&temp->buffer[temp->start], temp->end - temp->start); + temp = temp->next; + } + } + +/* +* Destroy this SecureQueue +*/ +void SecureQueue::destroy() + { + SecureQueueNode* temp = head; + while(temp) + { + SecureQueueNode* holder = temp->next; + delete temp; + temp = holder; + } + head = tail = nullptr; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue& SecureQueue::operator=(const SecureQueue& input) + { + destroy(); + head = tail = new SecureQueueNode; + SecureQueueNode* temp = input.head; + while(temp) + { + write(&temp->buffer[temp->start], temp->end - temp->start); + temp = temp->next; + } + return (*this); + } + +/* +* Add some bytes to the queue +*/ +void SecureQueue::write(const byte input[], size_t length) + { + if(!head) + head = tail = new SecureQueueNode; + while(length) + { + const size_t n = tail->write(input, length); + input += n; + length -= n; + if(length) + { + tail->next = new SecureQueueNode; + tail = tail->next; + } + } + } + +/* +* Read some bytes from the queue +*/ +size_t SecureQueue::read(byte output[], size_t length) + { + size_t got = 0; + while(length && head) + { + const size_t n = head->read(output, length); + output += n; + got += n; + length -= n; + if(head->size() == 0) + { + SecureQueueNode* holder = head->next; + delete head; + head = holder; + } + } + bytes_read += got; + return got; + } + +/* +* Read data, but do not remove it from queue +*/ +size_t SecureQueue::peek(byte output[], size_t length, size_t offset) const + { + SecureQueueNode* current = head; + + while(offset && current) + { + if(offset >= current->size()) + { + offset -= current->size(); + current = current->next; + } + else + break; + } + + size_t got = 0; + while(length && current) + { + const size_t n = current->peek(output, length, offset); + offset = 0; + output += n; + got += n; + length -= n; + current = current->next; + } + return got; + } + +/** +* Return how many bytes have been read so far. +*/ +size_t SecureQueue::get_bytes_read() const + { + return bytes_read; + } + +/* +* Return how many bytes the queue holds +*/ +size_t SecureQueue::size() const + { + SecureQueueNode* current = head; + size_t count = 0; + + while(current) + { + count += current->size(); + current = current->next; + } + return count; + } + +/* +* Test if the queue has any data in it +*/ +bool SecureQueue::end_of_data() const + { + return (size() == 0); + } + +bool SecureQueue::empty() const + { + return (size() == 0); + } + +} diff --git a/src/lib/filters/secqueue.h b/src/lib/filters/secqueue.h new file mode 100644 index 000000000..05c2e3db1 --- /dev/null +++ b/src/lib/filters/secqueue.h @@ -0,0 +1,69 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SECURE_QUEUE_H__ +#define BOTAN_SECURE_QUEUE_H__ + +#include +#include + +namespace Botan { + +/** +* A queue that knows how to zeroize itself +*/ +class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource + { + public: + std::string name() const { return "Queue"; } + + void write(const byte[], size_t); + + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t = 0) const; + size_t get_bytes_read() const; + + bool end_of_data() const; + + bool empty() const; + + /** + * @return number of bytes available in the queue + */ + size_t size() const; + + bool attachable() { return false; } + + /** + * SecureQueue assignment + * @param other the queue to copy + */ + SecureQueue& operator=(const SecureQueue& other); + + /** + * SecureQueue default constructor (creates empty queue) + */ + SecureQueue(); + + /** + * SecureQueue copy constructor + * @param other the queue to copy + */ + SecureQueue(const SecureQueue& other); + + ~SecureQueue() { destroy(); } + private: + size_t bytes_read; + void destroy(); + class SecureQueueNode* head; + class SecureQueueNode* tail; + }; + +} + +#endif diff --git a/src/lib/filters/threaded_fork.cpp b/src/lib/filters/threaded_fork.cpp new file mode 100644 index 000000000..05166d697 --- /dev/null +++ b/src/lib/filters/threaded_fork.cpp @@ -0,0 +1,146 @@ +/* +* Threaded Fork +* (C) 2013 Joel Low +* 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +struct Threaded_Fork_Data + { + /* + * Semaphore for indicating that there is work to be done (or to + * quit) + */ + Semaphore m_input_ready_semaphore; + + /* + * Ensures that all threads have completed processing data. + */ + Semaphore m_input_complete_semaphore; + + /* + * The work that needs to be done. This should be only when the threads + * are NOT running (i.e. before notifying the work condition, after + * the input_complete_semaphore is completely reset.) + */ + const byte* m_input = nullptr; + + /* + * The length of the work that needs to be done. + */ + size_t m_input_length = 0; + }; + +/* +* Threaded_Fork constructor +*/ +Threaded_Fork::Threaded_Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : + Fork(nullptr, static_cast(0)), + m_thread_data(new Threaded_Fork_Data) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Threaded_Fork constructor +*/ +Threaded_Fork::Threaded_Fork(Filter* filters[], size_t count) : + Fork(nullptr, static_cast(0)), + m_thread_data(new Threaded_Fork_Data) + { + set_next(filters, count); + } + +Threaded_Fork::~Threaded_Fork() + { + m_thread_data->m_input = nullptr; + m_thread_data->m_input_length = 0; + + m_thread_data->m_input_ready_semaphore.release(m_threads.size()); + + for(auto& thread : m_threads) + thread->join(); + } + +std::string Threaded_Fork::name() const + { + return "Threaded Fork"; + } + +void Threaded_Fork::set_next(Filter* f[], size_t n) + { + Fork::set_next(f, n); + n = next.size(); + + if(n < m_threads.size()) + m_threads.resize(n); + else + { + m_threads.reserve(n); + for(size_t i = m_threads.size(); i != n; ++i) + { + m_threads.push_back( + std::shared_ptr( + new std::thread( + std::bind(&Threaded_Fork::thread_entry, this, next[i])))); + } + } + } + +void Threaded_Fork::send(const byte input[], size_t length) + { + if(write_queue.size()) + thread_delegate_work(&write_queue[0], write_queue.size()); + thread_delegate_work(input, length); + + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + nothing_attached = false; + + if(nothing_attached) + write_queue += std::make_pair(input, length); + else + write_queue.clear(); + } + +void Threaded_Fork::thread_delegate_work(const byte input[], size_t length) + { + //Set the data to do. + m_thread_data->m_input = input; + m_thread_data->m_input_length = length; + + //Let the workers start processing. + m_thread_data->m_input_ready_semaphore.release(total_ports()); + + //Wait for all the filters to finish processing. + for(size_t i = 0; i != total_ports(); ++i) + m_thread_data->m_input_complete_semaphore.acquire(); + + //Reset the thread data + m_thread_data->m_input = nullptr; + m_thread_data->m_input_length = 0; + } + +void Threaded_Fork::thread_entry(Filter* filter) + { + while(true) + { + m_thread_data->m_input_ready_semaphore.acquire(); + + if(!m_thread_data->m_input) + break; + + filter->write(m_thread_data->m_input, m_thread_data->m_input_length); + m_thread_data->m_input_complete_semaphore.release(); + } + } + +} diff --git a/src/lib/filters/transform_filter.cpp b/src/lib/filters/transform_filter.cpp new file mode 100644 index 000000000..2f25aa2c5 --- /dev/null +++ b/src/lib/filters/transform_filter.cpp @@ -0,0 +1,100 @@ +/* +* Filter interface for Transformations +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +Transformation_Filter::Transformation_Filter(Transformation* transform) : + Buffered_Filter(transform->update_granularity(), + transform->minimum_final_size()), + m_nonce(transform->default_nonce_length() == 0), + m_transform(transform), + m_buffer(m_transform->update_granularity()) + { + } + +std::string Transformation_Filter::name() const + { + return ""; + //return m_transform->name(); + } + +void Transformation_Filter::Nonce_State::update(const InitializationVector& iv) + { + m_nonce = unlock(iv.bits_of()); + m_fresh_nonce = true; + } + +std::vector Transformation_Filter::Nonce_State::get() + { + BOTAN_ASSERT(m_fresh_nonce, "The nonce is fresh for this message"); + + if(!m_nonce.empty()) + m_fresh_nonce = false; + return m_nonce; + } + +void Transformation_Filter::set_iv(const InitializationVector& iv) + { + m_nonce.update(iv); + } + +void Transformation_Filter::set_key(const SymmetricKey& key) + { + m_transform->set_key(key); + } + +Key_Length_Specification Transformation_Filter::key_spec() const + { + return m_transform->key_spec(); + } + +bool Transformation_Filter::valid_iv_length(size_t length) const + { + return m_transform->valid_nonce_length(length); + } + +void Transformation_Filter::write(const byte input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void Transformation_Filter::end_msg() + { + Buffered_Filter::end_msg(); + } + +void Transformation_Filter::start_msg() + { + send(m_transform->start_vec(m_nonce.get())); + } + +void Transformation_Filter::buffered_block(const byte input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_transform->update_granularity(), input_length); + + m_buffer.assign(input, input + take); + m_transform->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Transformation_Filter::buffered_final(const byte input[], size_t input_length) + { + secure_vector buf(input, input + input_length); + m_transform->finish(buf); + send(buf); + } + +} diff --git a/src/lib/filters/transform_filter.h b/src/lib/filters/transform_filter.h new file mode 100644 index 000000000..c7033a060 --- /dev/null +++ b/src/lib/filters/transform_filter.h @@ -0,0 +1,69 @@ +/* +* Filter interface for Transformations +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TRANSFORMATION_FILTER_H__ +#define BOTAN_TRANSFORMATION_FILTER_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Filter interface for Transformations +*/ +class BOTAN_DLL Transformation_Filter : public Keyed_Filter, + private Buffered_Filter + { + public: + Transformation_Filter(Transformation* t); + + void set_iv(const InitializationVector& iv) override; + + void set_key(const SymmetricKey& key) override; + + Key_Length_Specification key_spec() const override; + + bool valid_iv_length(size_t length) const override; + + std::string name() const override; + + protected: + const Transformation& get_transform() const { return *m_transform; } + + Transformation& get_transform() { return *m_transform; } + + private: + void write(const byte input[], size_t input_length) override; + void start_msg() override; + void end_msg() override; + + void buffered_block(const byte input[], size_t input_length) override; + void buffered_final(const byte input[], size_t input_length) override; + + class Nonce_State + { + public: + Nonce_State(bool allow_null_nonce) : m_fresh_nonce(allow_null_nonce) {} + + void update(const InitializationVector& iv); + std::vector get(); + private: + bool m_fresh_nonce; + std::vector m_nonce; + }; + + Nonce_State m_nonce; + std::unique_ptr m_transform; + secure_vector m_buffer; + }; + +} + +#endif diff --git a/src/lib/hash/bmw_512/bmw_512.cpp b/src/lib/hash/bmw_512/bmw_512.cpp new file mode 100644 index 000000000..9dfa62214 --- /dev/null +++ b/src/lib/hash/bmw_512/bmw_512.cpp @@ -0,0 +1,204 @@ +/* +* Blue Midnight Wish 512 (Round 2 tweaked) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +inline u64bit S0(u64bit X) + { + return (X >> 1) ^ (X << 3) ^ rotate_left(X, 4) ^ rotate_left(X, 37); + } + +inline u64bit S1(u64bit X) + { + return (X >> 1) ^ (X << 2) ^ rotate_left(X, 13) ^ rotate_left(X, 43); + } + +inline u64bit S2(u64bit X) + { + return (X >> 2) ^ (X << 1) ^ rotate_left(X, 19) ^ rotate_left(X, 53); + } + +inline u64bit S3(u64bit X) + { + return (X >> 2) ^ (X << 2) ^ rotate_left(X, 28) ^ rotate_left(X, 59); + } + +inline u64bit S4(u64bit X) + { + return (X >> 1) ^ X; + } + +/** +* Blue Midnight Wish 512 compression function +*/ +void BMW_512_compress(u64bit H[16], const u64bit M[16], u64bit Q[32]) + { + const size_t EXPAND_1_ROUNDS = 2; + + for(size_t i = 0; i != 16; ++i) + Q[i] = H[i] ^ M[i]; + + Q[16] = Q[ 5] - Q[ 7] + Q[10] + Q[13] + Q[14]; + Q[17] = Q[ 6] - Q[ 8] + Q[11] + Q[14] - Q[15]; + Q[18] = Q[ 0] + Q[ 7] + Q[ 9] - Q[12] + Q[15]; + Q[19] = Q[ 0] - Q[ 1] + Q[ 8] - Q[10] + Q[13]; + Q[20] = Q[ 1] + Q[ 2] + Q[ 9] - Q[11] - Q[14]; + Q[21] = Q[ 3] - Q[ 2] + Q[10] - Q[12] + Q[15]; + Q[22] = Q[ 4] - Q[ 0] - Q[ 3] - Q[11] + Q[13]; + Q[23] = Q[ 1] - Q[ 4] - Q[ 5] - Q[12] - Q[14]; + Q[24] = Q[ 2] - Q[ 5] - Q[ 6] + Q[13] - Q[15]; + Q[25] = Q[ 0] - Q[ 3] + Q[ 6] - Q[ 7] + Q[14]; + Q[26] = Q[ 8] - Q[ 1] - Q[ 4] - Q[ 7] + Q[15]; + Q[27] = Q[ 8] - Q[ 0] - Q[ 2] - Q[ 5] + Q[ 9]; + Q[28] = Q[ 1] + Q[ 3] - Q[ 6] - Q[ 9] + Q[10]; + Q[29] = Q[ 2] + Q[ 4] + Q[ 7] + Q[10] + Q[11]; + Q[30] = Q[ 3] - Q[ 5] + Q[ 8] - Q[11] - Q[12]; + Q[31] = Q[12] - Q[ 4] - Q[ 6] - Q[ 9] + Q[13]; + + Q[ 0] = S0(Q[16]) + H[ 1]; + Q[ 1] = S1(Q[17]) + H[ 2]; + Q[ 2] = S2(Q[18]) + H[ 3]; + Q[ 3] = S3(Q[19]) + H[ 4]; + Q[ 4] = S4(Q[20]) + H[ 5]; + Q[ 5] = S0(Q[21]) + H[ 6]; + Q[ 6] = S1(Q[22]) + H[ 7]; + Q[ 7] = S2(Q[23]) + H[ 8]; + Q[ 8] = S3(Q[24]) + H[ 9]; + Q[ 9] = S4(Q[25]) + H[10]; + Q[10] = S0(Q[26]) + H[11]; + Q[11] = S1(Q[27]) + H[12]; + Q[12] = S2(Q[28]) + H[13]; + Q[13] = S3(Q[29]) + H[14]; + Q[14] = S4(Q[30]) + H[15]; + Q[15] = S0(Q[31]) + H[ 0]; + + const u64bit EXPANSION_CONSTANT = 0x0555555555555555; + + for(size_t i = 16; i != 16 + EXPAND_1_ROUNDS; ++i) + { + Q[i] = S1(Q[i-16]) + S2(Q[i-15]) + S3(Q[i-14]) + S0(Q[i-13]) + + S1(Q[i-12]) + S2(Q[i-11]) + S3(Q[i-10]) + S0(Q[i- 9]) + + S1(Q[i- 8]) + S2(Q[i- 7]) + S3(Q[i- 6]) + S0(Q[i- 5]) + + S1(Q[i- 4]) + S2(Q[i- 3]) + S3(Q[i- 2]) + S0(Q[i- 1]) + + ((rotate_left(M[(i-16) % 16], ((i-16)%16) + 1) + + rotate_left(M[(i-13) % 16], ((i-13)%16) + 1) - + rotate_left(M[(i- 6) % 16], ((i-6)%16) + 1) + + (EXPANSION_CONSTANT * i)) ^ H[(i-16+7)%16]); + } + + for(size_t i = 16 + EXPAND_1_ROUNDS; i != 32; ++i) + { + Q[i] = Q[i-16] + rotate_left(Q[i-15], 5) + + Q[i-14] + rotate_left(Q[i-13], 11) + + Q[i-12] + rotate_left(Q[i-11], 27) + + Q[i-10] + rotate_left(Q[i- 9], 32) + + Q[i- 8] + rotate_left(Q[i- 7], 37) + + Q[i- 6] + rotate_left(Q[i- 5], 43) + + Q[i- 4] + rotate_left(Q[i- 3], 53) + + S4(Q[i - 2]) + ((Q[i-1] >> 2) ^ Q[i-1]) + + ((rotate_left(M[(i-16) % 16], ((i-16)%16 + 1)) + + rotate_left(M[(i-13) % 16], ((i-13)%16 + 1)) - + rotate_left(M[(i- 6) % 16], ((i-6)%16 + 1)) + + (EXPANSION_CONSTANT * i)) ^ H[(i-16+7)%16]); + } + + u64bit XL = Q[16] ^ Q[17] ^ Q[18] ^ Q[19] ^ + Q[20] ^ Q[21] ^ Q[22] ^ Q[23]; + + u64bit XH = Q[24] ^ Q[25] ^ Q[26] ^ Q[27] ^ + Q[28] ^ Q[29] ^ Q[30] ^ Q[31]; + + XH ^= XL; + + H[ 0] = ((XH << 5) ^ (Q[16] >> 5) ^ M[0]) + (XL ^ Q[24] ^ Q[0]); + H[ 1] = ((XH >> 7) ^ (Q[17] << 8) ^ M[1]) + (XL ^ Q[25] ^ Q[1]); + H[ 2] = ((XH >> 5) ^ (Q[18] << 5) ^ M[2]) + (XL ^ Q[26] ^ Q[2]); + H[ 3] = ((XH >> 1) ^ (Q[19] << 5) ^ M[3]) + (XL ^ Q[27] ^ Q[3]); + H[ 4] = ((XH >> 3) ^ (Q[20] ) ^ M[4]) + (XL ^ Q[28] ^ Q[4]); + H[ 5] = ((XH << 6) ^ (Q[21] >> 6) ^ M[5]) + (XL ^ Q[29] ^ Q[5]); + H[ 6] = ((XH >> 4) ^ (Q[22] << 6) ^ M[6]) + (XL ^ Q[30] ^ Q[6]); + H[ 7] = ((XH >> 11) ^ (Q[23] << 2) ^ M[7]) + (XL ^ Q[31] ^ Q[7]); + + H[ 8] = rotate_left(H[4], 9) + (XH ^ Q[24] ^ M[ 8]) + ((XL << 8) ^ Q[23] ^ Q[ 8]); + H[ 9] = rotate_left(H[5], 10) + (XH ^ Q[25] ^ M[ 9]) + ((XL >> 6) ^ Q[16] ^ Q[ 9]); + H[10] = rotate_left(H[6], 11) + (XH ^ Q[26] ^ M[10]) + ((XL << 6) ^ Q[17] ^ Q[10]); + H[11] = rotate_left(H[7], 12) + (XH ^ Q[27] ^ M[11]) + ((XL << 4) ^ Q[18] ^ Q[11]); + H[12] = rotate_left(H[0], 13) + (XH ^ Q[28] ^ M[12]) + ((XL >> 3) ^ Q[19] ^ Q[12]); + H[13] = rotate_left(H[1], 14) + (XH ^ Q[29] ^ M[13]) + ((XL >> 4) ^ Q[20] ^ Q[13]); + H[14] = rotate_left(H[2], 15) + (XH ^ Q[30] ^ M[14]) + ((XL >> 7) ^ Q[21] ^ Q[14]); + H[15] = rotate_left(H[3], 16) + (XH ^ Q[31] ^ M[15]) + ((XL >> 2) ^ Q[22] ^ Q[15]); + } + +} + +void BMW_512::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + BMW_512_compress(&H[0], &M[0], &Q[0]); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void BMW_512::copy_out(byte output[]) + { + u64bit final[16] = { + 0xAAAAAAAAAAAAAAA0, 0xAAAAAAAAAAAAAAA1, + 0xAAAAAAAAAAAAAAA2, 0xAAAAAAAAAAAAAAA3, + 0xAAAAAAAAAAAAAAA4, 0xAAAAAAAAAAAAAAA5, + 0xAAAAAAAAAAAAAAA6, 0xAAAAAAAAAAAAAAA7, + 0xAAAAAAAAAAAAAAA8, 0xAAAAAAAAAAAAAAA9, + 0xAAAAAAAAAAAAAAAA, 0xAAAAAAAAAAAAAAAB, + 0xAAAAAAAAAAAAAAAC, 0xAAAAAAAAAAAAAAAD, + 0xAAAAAAAAAAAAAAAE, 0xAAAAAAAAAAAAAAAF }; + + BMW_512_compress(final, &H[0], &Q[0]); + + for(size_t i = 0; i != output_length(); i += 8) + store_le(final[8 + i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void BMW_512::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + zeroise(Q); + + H[ 0] = 0x8081828384858687; + H[ 1] = 0x88898A8B8C8D8E8F; + H[ 2] = 0x9091929394959697; + H[ 3] = 0x98999A9B9C9D9E9F; + H[ 4] = 0xA0A1A2A3A4A5A6A7; + H[ 5] = 0xA8A9AAABACADAEAF; + H[ 6] = 0xB0B1B2B3B4B5B6B7; + H[ 7] = 0xB8B9BABBBCBDBEBF; + H[ 8] = 0xC0C1C2C3C4C5C6C7; + H[ 9] = 0xC8C9CACBCCCDCECF; + H[10] = 0xD0D1D2D3D4D5D6D7; + H[11] = 0xD8D9DADBDCDDDEDF; + H[12] = 0xE0E1E2E3E4E5E6E7; + H[13] = 0xE8E9EAEBECEDEEEF; + H[14] = 0xF0F1F2F3F4F5F6F7; + H[15] = 0xF8F9FAFBFCFDFEFF; + } + +} diff --git a/src/lib/hash/bmw_512/bmw_512.h b/src/lib/hash/bmw_512/bmw_512.h new file mode 100644 index 000000000..b9ea63578 --- /dev/null +++ b/src/lib/hash/bmw_512/bmw_512.h @@ -0,0 +1,38 @@ +/* +* Blue Midnight Wish 512 (Round 2 tweaked) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BMW_512_H__ +#define BOTAN_BMW_512_H__ + +#include + +namespace Botan { + +/** +* Blue Midnight Wish 512 (Round 2 tweaked version) +*/ +class BOTAN_DLL BMW_512 : public MDx_HashFunction + { + public: + std::string name() const { return "BMW512"; } + size_t output_length() const { return 64; } + HashFunction* clone() const { return new BMW_512; } + + void clear(); + + BMW_512() : MDx_HashFunction(128, false, true), H(16), M(16), Q(32) + { clear(); } + private: + void compress_n(const byte input[], size_t blocks); + void copy_out(byte output[]); + + secure_vector H, M, Q; + }; + +} + +#endif diff --git a/src/lib/hash/bmw_512/info.txt b/src/lib/hash/bmw_512/info.txt new file mode 100644 index 000000000..94dcbdd85 --- /dev/null +++ b/src/lib/hash/bmw_512/info.txt @@ -0,0 +1,5 @@ +define BMW_512 20131128 + + +mdx_hash + diff --git a/src/lib/hash/comb4p/comb4p.cpp b/src/lib/hash/comb4p/comb4p.cpp new file mode 100644 index 000000000..7aec5972e --- /dev/null +++ b/src/lib/hash/comb4p/comb4p.cpp @@ -0,0 +1,102 @@ +/* +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +void comb4p_round(secure_vector& out, + const secure_vector& in, + byte round_no, + HashFunction* h1, + HashFunction* h2) + { + h1->update(round_no); + h2->update(round_no); + + h1->update(&in[0], in.size()); + h2->update(&in[0], in.size()); + + secure_vector h_buf = h1->final(); + xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size())); + + h_buf = h2->final(); + xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size())); + } + +} + +Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) : + hash1(h1), hash2(h2) + { + if(hash1->name() == hash2->name()) + throw std::invalid_argument("Comb4P: Must use two distinct hashes"); + + if(hash1->output_length() != hash2->output_length()) + throw std::invalid_argument("Comb4P: Incompatible hashes " + + hash1->name() + " and " + + hash2->name()); + + clear(); + } + +size_t Comb4P::hash_block_size() const + { + if(hash1->hash_block_size() == hash2->hash_block_size()) + return hash1->hash_block_size(); + + /* + * Return LCM of the block sizes? This would probably be OK for + * HMAC, which is the main thing relying on knowing the block size. + */ + return 0; + } + +void Comb4P::clear() + { + hash1->clear(); + hash2->clear(); + + // Prep for processing next message, if any + hash1->update(0); + hash2->update(0); + } + +void Comb4P::add_data(const byte input[], size_t length) + { + hash1->update(input, length); + hash2->update(input, length); + } + +void Comb4P::final_result(byte out[]) + { + secure_vector h1 = hash1->final(); + secure_vector h2 = hash2->final(); + + // First round + xor_buf(&h1[0], &h2[0], std::min(h1.size(), h2.size())); + + // Second round + comb4p_round(h2, h1, 1, hash1, hash2); + + // Third round + comb4p_round(h1, h2, 2, hash1, hash2); + + copy_mem(out , &h1[0], h1.size()); + copy_mem(out + h1.size(), &h2[0], h2.size()); + + // Prep for processing next message, if any + hash1->update(0); + hash2->update(0); + } + +} + diff --git a/src/lib/hash/comb4p/comb4p.h b/src/lib/hash/comb4p/comb4p.h new file mode 100644 index 000000000..e0cffc22b --- /dev/null +++ b/src/lib/hash/comb4p/comb4p.h @@ -0,0 +1,61 @@ +/* +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_COMB4P_H__ +#define BOTAN_COMB4P_H__ + +#include + +namespace Botan { + +/** +* Combines two hash functions using a Feistel scheme. Described in +* "On the Security of Hash Function Combiners", Anja Lehmann +*/ +class BOTAN_DLL Comb4P : public HashFunction + { + public: + /** + * @param h1 the first hash + * @param h2 the second hash + */ + Comb4P(HashFunction* h1, HashFunction* h2); + + Comb4P(const Comb4P&) = delete; + Comb4P& operator=(const Comb4P&) = delete; + + ~Comb4P() { delete hash1; delete hash2; } + + size_t hash_block_size() const; + + size_t output_length() const + { + return hash1->output_length() + hash2->output_length(); + } + + HashFunction* clone() const + { + return new Comb4P(hash1->clone(), hash2->clone()); + } + + std::string name() const + { + return "Comb4P(" + hash1->name() + "," + hash2->name() + ")"; + } + + void clear(); + private: + void add_data(const byte input[], size_t length); + void final_result(byte out[]); + + HashFunction* hash1; + HashFunction* hash2; + }; + +} + +#endif diff --git a/src/lib/hash/comb4p/info.txt b/src/lib/hash/comb4p/info.txt new file mode 100644 index 000000000..375895610 --- /dev/null +++ b/src/lib/hash/comb4p/info.txt @@ -0,0 +1 @@ +define COMB4P 20131128 diff --git a/src/lib/hash/gost_3411/gost_3411.cpp b/src/lib/hash/gost_3411/gost_3411.cpp new file mode 100644 index 000000000..eb889c0a5 --- /dev/null +++ b/src/lib/hash/gost_3411/gost_3411.cpp @@ -0,0 +1,242 @@ +/* +* GOST 34.11 +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/** +* GOST 34.11 Constructor +*/ +GOST_34_11::GOST_34_11() : + cipher(GOST_28147_89_Params("R3411_CryptoPro")), + buffer(32), + sum(32), + hash(32) + { + count = 0; + position = 0; + } + +void GOST_34_11::clear() + { + cipher.clear(); + zeroise(sum); + zeroise(hash); + count = 0; + position = 0; + } + +/** +* Hash additional inputs +*/ +void GOST_34_11::add_data(const byte input[], size_t length) + { + count += length; + + if(position) + { + buffer_insert(buffer, position, input, length); + + if(position + length >= hash_block_size()) + { + compress_n(&buffer[0], 1); + input += (hash_block_size() - position); + length -= (hash_block_size() - position); + position = 0; + } + } + + const size_t full_blocks = length / hash_block_size(); + const size_t remaining = length % hash_block_size(); + + if(full_blocks) + compress_n(input, full_blocks); + + buffer_insert(buffer, position, input + full_blocks * hash_block_size(), remaining); + position += remaining; + } + +/** +* The GOST 34.11 compression function +*/ +void GOST_34_11::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + for(u16bit j = 0, carry = 0; j != 32; ++j) + { + u16bit s = sum[j] + input[32*i+j] + carry; + carry = get_byte(0, s); + sum[j] = get_byte(1, s); + } + + byte S[32] = { 0 }; + + u64bit U[4], V[4]; + load_be(U, &hash[0], 4); + load_be(V, input + 32*i, 4); + + for(size_t j = 0; j != 4; ++j) + { + byte key[32] = { 0 }; + + // P transformation + for(size_t k = 0; k != 4; ++k) + for(size_t l = 0; l != 8; ++l) + key[4*l+k] = get_byte(l, U[k]) ^ get_byte(l, V[k]); + + cipher.set_key(key, 32); + cipher.encrypt(&hash[8*j], S + 8*j); + + if(j == 3) + break; + + // A(x) + u64bit A_U = U[0]; + U[0] = U[1]; + U[1] = U[2]; + U[2] = U[3]; + U[3] = U[0] ^ A_U; + + if(j == 1) // C_3 + { + U[0] ^= 0x00FF00FF00FF00FF; + U[1] ^= 0xFF00FF00FF00FF00; + U[2] ^= 0x00FFFF00FF0000FF; + U[3] ^= 0xFF000000FFFF00FF; + } + + // A(A(x)) + u64bit AA_V_1 = V[0] ^ V[1]; + u64bit AA_V_2 = V[1] ^ V[2]; + V[0] = V[2]; + V[1] = V[3]; + V[2] = AA_V_1; + V[3] = AA_V_2; + } + + byte S2[32] = { 0 }; + + // 12 rounds of psi + S2[ 0] = S[24]; + S2[ 1] = S[25]; + S2[ 2] = S[26]; + S2[ 3] = S[27]; + S2[ 4] = S[28]; + S2[ 5] = S[29]; + S2[ 6] = S[30]; + S2[ 7] = S[31]; + S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30]; + S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31]; + S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30]; + S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31]; + S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28]; + S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29]; + S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30]; + S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31]; + S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28]; + S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29]; + S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30]; + S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31]; + S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30]; + S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31]; + S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26]; + S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27]; + S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28]; + S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29]; + S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; + S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; + S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28]; + S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29]; + + xor_buf(S, S2, input + 32*i, 32); + + S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30]; + S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31]; + + copy_mem(S, S+2, 30); + S[30] = S2[0]; + S[31] = S2[1]; + + xor_buf(S, &hash[0], 32); + + // 61 rounds of psi + S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; + S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; + S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28]; + S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29]; + S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30]; + S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31]; + S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30]; + S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31]; + S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28]; + S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29]; + S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30]; + S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31]; + S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24]; + S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25]; + S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26]; + S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27]; + S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28]; + S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29]; + S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30]; + S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31]; + S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^ + S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^ + S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^ + S[24] ^ S[26] ^ S[28]; + S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^ + S[25] ^ S[27] ^ S[29]; + S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^ + S[26] ^ S[28] ^ S[30]; + S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^ + S[27] ^ S[29] ^ S[31]; + S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28]; + S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29]; + S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30]; + S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31]; + + copy_mem(&hash[0], &S2[0], 32); + } + } + +/** +* Produce the final GOST 34.11 output +*/ +void GOST_34_11::final_result(byte out[]) + { + if(position) + { + clear_mem(&buffer[0] + position, buffer.size() - position); + compress_n(&buffer[0], 1); + } + + secure_vector length_buf(32); + const u64bit bit_count = count * 8; + store_le(bit_count, &length_buf[0]); + + secure_vector sum_buf = sum; + + compress_n(&length_buf[0], 1); + compress_n(&sum_buf[0], 1); + + copy_mem(out, &hash[0], 32); + + clear(); + } + +} diff --git a/src/lib/hash/gost_3411/gost_3411.h b/src/lib/hash/gost_3411/gost_3411.h new file mode 100644 index 000000000..5437ca4d8 --- /dev/null +++ b/src/lib/hash/gost_3411/gost_3411.h @@ -0,0 +1,44 @@ +/* +* GOST 34.11 +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GOST_3411_H__ +#define BOTAN_GOST_3411_H__ + +#include +#include + +namespace Botan { + +/** +* GOST 34.11 +*/ +class BOTAN_DLL GOST_34_11 : public HashFunction + { + public: + std::string name() const { return "GOST-R-34.11-94" ; } + size_t output_length() const { return 32; } + size_t hash_block_size() const { return 32; } + HashFunction* clone() const { return new GOST_34_11; } + + void clear(); + + GOST_34_11(); + private: + void compress_n(const byte input[], size_t blocks); + + void add_data(const byte[], size_t); + void final_result(byte[]); + + GOST_28147_89 cipher; + secure_vector buffer, sum, hash; + size_t position; + u64bit count; + }; + +} + +#endif diff --git a/src/lib/hash/gost_3411/info.txt b/src/lib/hash/gost_3411/info.txt new file mode 100644 index 000000000..af8eddac6 --- /dev/null +++ b/src/lib/hash/gost_3411/info.txt @@ -0,0 +1,5 @@ +define GOST_34_11 20131128 + + +gost_28147 + diff --git a/src/lib/hash/has160/has160.cpp b/src/lib/hash/has160/has160.cpp new file mode 100644 index 000000000..6890ccb85 --- /dev/null +++ b/src/lib/hash/has160/has160.cpp @@ -0,0 +1,165 @@ +/* +* HAS-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace HAS_160_F { + +/* +* HAS-160 F1 Function +*/ +inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (D ^ (B & (C ^ D))) + msg; + B = rotate_left(B, 10); + } + +/* +* HAS-160 F2 Function +*/ +inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (B ^ C ^ D) + msg + 0x5A827999; + B = rotate_left(B, 17); + } + +/* +* HAS-160 F3 Function +*/ +inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (C ^ (B | ~D)) + msg + 0x6ED9EBA1; + B = rotate_left(B, 25); + } + +/* +* HAS-160 F4 Function +*/ +inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (B ^ C ^ D) + msg + 0x8F1BBCDC; + B = rotate_left(B, 30); + } + +} + +/* +* HAS-160 Compression Function +*/ +void HAS_160::compress_n(const byte input[], size_t blocks) + { + using namespace HAS_160_F; + + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&X[0], input, 16); + + X[16] = X[ 0] ^ X[ 1] ^ X[ 2] ^ X[ 3]; + X[17] = X[ 4] ^ X[ 5] ^ X[ 6] ^ X[ 7]; + X[18] = X[ 8] ^ X[ 9] ^ X[10] ^ X[11]; + X[19] = X[12] ^ X[13] ^ X[14] ^ X[15]; + F1(A,B,C,D,E,X[18], 5); F1(E,A,B,C,D,X[ 0],11); + F1(D,E,A,B,C,X[ 1], 7); F1(C,D,E,A,B,X[ 2],15); + F1(B,C,D,E,A,X[ 3], 6); F1(A,B,C,D,E,X[19],13); + F1(E,A,B,C,D,X[ 4], 8); F1(D,E,A,B,C,X[ 5],14); + F1(C,D,E,A,B,X[ 6], 7); F1(B,C,D,E,A,X[ 7],12); + F1(A,B,C,D,E,X[16], 9); F1(E,A,B,C,D,X[ 8],11); + F1(D,E,A,B,C,X[ 9], 8); F1(C,D,E,A,B,X[10],15); + F1(B,C,D,E,A,X[11], 6); F1(A,B,C,D,E,X[17],12); + F1(E,A,B,C,D,X[12], 9); F1(D,E,A,B,C,X[13],14); + F1(C,D,E,A,B,X[14], 5); F1(B,C,D,E,A,X[15],13); + + X[16] = X[ 3] ^ X[ 6] ^ X[ 9] ^ X[12]; + X[17] = X[ 2] ^ X[ 5] ^ X[ 8] ^ X[15]; + X[18] = X[ 1] ^ X[ 4] ^ X[11] ^ X[14]; + X[19] = X[ 0] ^ X[ 7] ^ X[10] ^ X[13]; + F2(A,B,C,D,E,X[18], 5); F2(E,A,B,C,D,X[ 3],11); + F2(D,E,A,B,C,X[ 6], 7); F2(C,D,E,A,B,X[ 9],15); + F2(B,C,D,E,A,X[12], 6); F2(A,B,C,D,E,X[19],13); + F2(E,A,B,C,D,X[15], 8); F2(D,E,A,B,C,X[ 2],14); + F2(C,D,E,A,B,X[ 5], 7); F2(B,C,D,E,A,X[ 8],12); + F2(A,B,C,D,E,X[16], 9); F2(E,A,B,C,D,X[11],11); + F2(D,E,A,B,C,X[14], 8); F2(C,D,E,A,B,X[ 1],15); + F2(B,C,D,E,A,X[ 4], 6); F2(A,B,C,D,E,X[17],12); + F2(E,A,B,C,D,X[ 7], 9); F2(D,E,A,B,C,X[10],14); + F2(C,D,E,A,B,X[13], 5); F2(B,C,D,E,A,X[ 0],13); + + X[16] = X[ 5] ^ X[ 7] ^ X[12] ^ X[14]; + X[17] = X[ 0] ^ X[ 2] ^ X[ 9] ^ X[11]; + X[18] = X[ 4] ^ X[ 6] ^ X[13] ^ X[15]; + X[19] = X[ 1] ^ X[ 3] ^ X[ 8] ^ X[10]; + F3(A,B,C,D,E,X[18], 5); F3(E,A,B,C,D,X[12],11); + F3(D,E,A,B,C,X[ 5], 7); F3(C,D,E,A,B,X[14],15); + F3(B,C,D,E,A,X[ 7], 6); F3(A,B,C,D,E,X[19],13); + F3(E,A,B,C,D,X[ 0], 8); F3(D,E,A,B,C,X[ 9],14); + F3(C,D,E,A,B,X[ 2], 7); F3(B,C,D,E,A,X[11],12); + F3(A,B,C,D,E,X[16], 9); F3(E,A,B,C,D,X[ 4],11); + F3(D,E,A,B,C,X[13], 8); F3(C,D,E,A,B,X[ 6],15); + F3(B,C,D,E,A,X[15], 6); F3(A,B,C,D,E,X[17],12); + F3(E,A,B,C,D,X[ 8], 9); F3(D,E,A,B,C,X[ 1],14); + F3(C,D,E,A,B,X[10], 5); F3(B,C,D,E,A,X[ 3],13); + + X[16] = X[ 2] ^ X[ 7] ^ X[ 8] ^ X[13]; + X[17] = X[ 3] ^ X[ 4] ^ X[ 9] ^ X[14]; + X[18] = X[ 0] ^ X[ 5] ^ X[10] ^ X[15]; + X[19] = X[ 1] ^ X[ 6] ^ X[11] ^ X[12]; + F4(A,B,C,D,E,X[18], 5); F4(E,A,B,C,D,X[ 7],11); + F4(D,E,A,B,C,X[ 2], 7); F4(C,D,E,A,B,X[13],15); + F4(B,C,D,E,A,X[ 8], 6); F4(A,B,C,D,E,X[19],13); + F4(E,A,B,C,D,X[ 3], 8); F4(D,E,A,B,C,X[14],14); + F4(C,D,E,A,B,X[ 9], 7); F4(B,C,D,E,A,X[ 4],12); + F4(A,B,C,D,E,X[16], 9); F4(E,A,B,C,D,X[15],11); + F4(D,E,A,B,C,X[10], 8); F4(C,D,E,A,B,X[ 5],15); + F4(B,C,D,E,A,X[ 0], 6); F4(A,B,C,D,E,X[17],12); + F4(E,A,B,C,D,X[11], 9); F4(D,E,A,B,C,X[ 6],14); + F4(C,D,E,A,B,X[ 1], 5); F4(B,C,D,E,A,X[12],13); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void HAS_160::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void HAS_160::clear() + { + MDx_HashFunction::clear(); + zeroise(X); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} diff --git a/src/lib/hash/has160/has160.h b/src/lib/hash/has160/has160.h new file mode 100644 index 000000000..9947d9580 --- /dev/null +++ b/src/lib/hash/has160/has160.h @@ -0,0 +1,39 @@ +/* +* HAS-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HAS_160_H__ +#define BOTAN_HAS_160_H__ + +#include + +namespace Botan { + +/** +* HAS-160, a Korean hash function standardized in +* TTAS.KO-12.0011/R1. Used in conjuction with KCDSA +*/ +class BOTAN_DLL HAS_160 : public MDx_HashFunction + { + public: + std::string name() const { return "HAS-160"; } + size_t output_length() const { return 20; } + HashFunction* clone() const { return new HAS_160; } + + void clear(); + + HAS_160() : MDx_HashFunction(64, false, true), X(20), digest(5) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector X, digest; + }; + +} + +#endif diff --git a/src/lib/hash/has160/info.txt b/src/lib/hash/has160/info.txt new file mode 100644 index 000000000..cf403dad5 --- /dev/null +++ b/src/lib/hash/has160/info.txt @@ -0,0 +1,5 @@ +define HAS_160 20131128 + + +mdx_hash + diff --git a/src/lib/hash/hash.h b/src/lib/hash/hash.h new file mode 100644 index 000000000..1e4b045e2 --- /dev/null +++ b/src/lib/hash/hash.h @@ -0,0 +1,37 @@ +/* +* Hash Function Base Class +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HASH_FUNCTION_BASE_CLASS_H__ +#define BOTAN_HASH_FUNCTION_BASE_CLASS_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents hash function (message digest) objects +*/ +class BOTAN_DLL HashFunction : public Buffered_Computation, + public Algorithm + { + public: + /** + * @return new object representing the same algorithm as *this + */ + virtual HashFunction* clone() const = 0; + + /** + * @return hash block size as defined for this algorithm + */ + virtual size_t hash_block_size() const { return 0; } + }; + +} + +#endif diff --git a/src/lib/hash/info.txt b/src/lib/hash/info.txt new file mode 100644 index 000000000..d991577f7 --- /dev/null +++ b/src/lib/hash/info.txt @@ -0,0 +1,3 @@ + +algo_base + diff --git a/src/lib/hash/keccak/info.txt b/src/lib/hash/keccak/info.txt new file mode 100644 index 000000000..ecdfba19c --- /dev/null +++ b/src/lib/hash/keccak/info.txt @@ -0,0 +1,5 @@ +define KECCAK 20131128 + + +alloc + diff --git a/src/lib/hash/keccak/keccak.cpp b/src/lib/hash/keccak/keccak.cpp new file mode 100644 index 000000000..e34c0fd43 --- /dev/null +++ b/src/lib/hash/keccak/keccak.cpp @@ -0,0 +1,198 @@ +/* +* Keccak +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void keccak_f_1600(u64bit A[25]) + { + static const u64bit RC[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, + 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, + 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + + for(size_t i = 0; i != 24; ++i) + { + const u64bit C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20]; + const u64bit C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21]; + const u64bit C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22]; + const u64bit C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23]; + const u64bit C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]; + + const u64bit D0 = rotate_left(C0, 1) ^ C3; + const u64bit D1 = rotate_left(C1, 1) ^ C4; + const u64bit D2 = rotate_left(C2, 1) ^ C0; + const u64bit D3 = rotate_left(C3, 1) ^ C1; + const u64bit D4 = rotate_left(C4, 1) ^ C2; + + const u64bit B00 = A[ 0] ^ D1; + const u64bit B01 = rotate_left(A[ 6] ^ D2, 44); + const u64bit B02 = rotate_left(A[12] ^ D3, 43); + const u64bit B03 = rotate_left(A[18] ^ D4, 21); + const u64bit B04 = rotate_left(A[24] ^ D0, 14); + const u64bit B05 = rotate_left(A[ 3] ^ D4, 28); + const u64bit B06 = rotate_left(A[ 9] ^ D0, 20); + const u64bit B07 = rotate_left(A[10] ^ D1, 3); + const u64bit B08 = rotate_left(A[16] ^ D2, 45); + const u64bit B09 = rotate_left(A[22] ^ D3, 61); + const u64bit B10 = rotate_left(A[ 1] ^ D2, 1); + const u64bit B11 = rotate_left(A[ 7] ^ D3, 6); + const u64bit B12 = rotate_left(A[13] ^ D4, 25); + const u64bit B13 = rotate_left(A[19] ^ D0, 8); + const u64bit B14 = rotate_left(A[20] ^ D1, 18); + const u64bit B15 = rotate_left(A[ 4] ^ D0, 27); + const u64bit B16 = rotate_left(A[ 5] ^ D1, 36); + const u64bit B17 = rotate_left(A[11] ^ D2, 10); + const u64bit B18 = rotate_left(A[17] ^ D3, 15); + const u64bit B19 = rotate_left(A[23] ^ D4, 56); + const u64bit B20 = rotate_left(A[ 2] ^ D3, 62); + const u64bit B21 = rotate_left(A[ 8] ^ D4, 55); + const u64bit B22 = rotate_left(A[14] ^ D0, 39); + const u64bit B23 = rotate_left(A[15] ^ D1, 41); + const u64bit B24 = rotate_left(A[21] ^ D2, 2); + + A[ 0] = B00 ^ (~B01 & B02); + A[ 1] = B01 ^ (~B02 & B03); + A[ 2] = B02 ^ (~B03 & B04); + A[ 3] = B03 ^ (~B04 & B00); + A[ 4] = B04 ^ (~B00 & B01); + A[ 5] = B05 ^ (~B06 & B07); + A[ 6] = B06 ^ (~B07 & B08); + A[ 7] = B07 ^ (~B08 & B09); + A[ 8] = B08 ^ (~B09 & B05); + A[ 9] = B09 ^ (~B05 & B06); + A[10] = B10 ^ (~B11 & B12); + A[11] = B11 ^ (~B12 & B13); + A[12] = B12 ^ (~B13 & B14); + A[13] = B13 ^ (~B14 & B10); + A[14] = B14 ^ (~B10 & B11); + A[15] = B15 ^ (~B16 & B17); + A[16] = B16 ^ (~B17 & B18); + A[17] = B17 ^ (~B18 & B19); + A[18] = B18 ^ (~B19 & B15); + A[19] = B19 ^ (~B15 & B16); + A[20] = B20 ^ (~B21 & B22); + A[21] = B21 ^ (~B22 & B23); + A[22] = B22 ^ (~B23 & B24); + A[23] = B23 ^ (~B24 & B20); + A[24] = B24 ^ (~B20 & B21); + + A[0] ^= RC[i]; + } + } + +} + +Keccak_1600::Keccak_1600(size_t output_bits) : + output_bits(output_bits), + bitrate(1600 - 2*output_bits), + S(25), + S_pos(0) + { + // We only support the parameters for the SHA-3 proposal + + if(output_bits != 224 && output_bits != 256 && + output_bits != 384 && output_bits != 512) + throw Invalid_Argument("Keccak_1600: Invalid output length " + + std::to_string(output_bits)); + } + +std::string Keccak_1600::name() const + { + return "Keccak-1600(" + std::to_string(output_bits) + ")"; + } + +HashFunction* Keccak_1600::clone() const + { + return new Keccak_1600(output_bits); + } + +void Keccak_1600::clear() + { + zeroise(S); + S_pos = 0; + } + +void Keccak_1600::add_data(const byte input[], size_t length) + { + if(length == 0) + return; + + while(length) + { + size_t to_take = std::min(length, bitrate / 8 - S_pos); + + length -= to_take; + + while(to_take && S_pos % 8) + { + S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); + + ++S_pos; + ++input; + --to_take; + } + + while(to_take && to_take % 8 == 0) + { + S[S_pos / 8] ^= load_le(input, 0); + S_pos += 8; + input += 8; + to_take -= 8; + } + + while(to_take) + { + S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); + + ++S_pos; + ++input; + --to_take; + } + + if(S_pos == bitrate / 8) + { + keccak_f_1600(&S[0]); + S_pos = 0; + } + } + } + +void Keccak_1600::final_result(byte output[]) + { + std::vector padding(bitrate / 8 - S_pos); + + padding[0] = 0x01; + padding[padding.size()-1] |= 0x80; + + add_data(&padding[0], padding.size()); + + /* + * We never have to run the permutation again because we only support + * limited output lengths + */ + for(size_t i = 0; i != output_bits/8; ++i) + output[i] = get_byte(7 - (i % 8), S[i/8]); + + clear(); + } + +} diff --git a/src/lib/hash/keccak/keccak.h b/src/lib/hash/keccak/keccak.h new file mode 100644 index 000000000..e91a04d32 --- /dev/null +++ b/src/lib/hash/keccak/keccak.h @@ -0,0 +1,47 @@ +/* +* Keccak +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KECCAK_H__ +#define BOTAN_KECCAK_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Keccak[1600], a SHA-3 candidate +*/ +class BOTAN_DLL Keccak_1600 : public HashFunction + { + public: + + /** + * @param output_bits the size of the hash output; must be one of + * 224, 256, 384, or 512 + */ + Keccak_1600(size_t output_bits = 512); + + size_t hash_block_size() const { return bitrate / 8; } + size_t output_length() const { return output_bits / 8; } + + HashFunction* clone() const; + std::string name() const; + void clear(); + private: + void add_data(const byte input[], size_t length); + void final_result(byte out[]); + + size_t output_bits, bitrate; + secure_vector S; + size_t S_pos; + }; + +} + +#endif diff --git a/src/lib/hash/md2/info.txt b/src/lib/hash/md2/info.txt new file mode 100644 index 000000000..8ea7dc393 --- /dev/null +++ b/src/lib/hash/md2/info.txt @@ -0,0 +1 @@ +define MD2 20131128 diff --git a/src/lib/hash/md2/md2.cpp b/src/lib/hash/md2/md2.cpp new file mode 100644 index 000000000..8f6a90208 --- /dev/null +++ b/src/lib/hash/md2/md2.cpp @@ -0,0 +1,113 @@ +/* +* MD2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/** +* MD2 Compression Function +*/ +void MD2::hash(const byte input[]) + { + static const byte SBOX[256] = { + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, + 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, + 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, + 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, + 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 0x80, 0x7F, 0x5D, 0x9A, + 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, + 0xAC, 0x56, 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, 0x70, 0x59, + 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, + 0x34, 0x40, 0x7E, 0x0F, 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, + 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, + 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, + 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, + 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, + 0x9F, 0x11, 0x83, 0x14 }; + + buffer_insert(X, 16, input, hash_block_size()); + xor_buf(&X[32], &X[0], &X[16], hash_block_size()); + byte T = 0; + + for(size_t i = 0; i != 18; ++i) + { + for(size_t k = 0; k != 48; k += 8) + { + T = X[k ] ^= SBOX[T]; T = X[k+1] ^= SBOX[T]; + T = X[k+2] ^= SBOX[T]; T = X[k+3] ^= SBOX[T]; + T = X[k+4] ^= SBOX[T]; T = X[k+5] ^= SBOX[T]; + T = X[k+6] ^= SBOX[T]; T = X[k+7] ^= SBOX[T]; + } + + T += static_cast(i); + } + + T = checksum[15]; + for(size_t i = 0; i != hash_block_size(); ++i) + T = checksum[i] ^= SBOX[input[i] ^ T]; + } + +/** +* Update the hash +*/ +void MD2::add_data(const byte input[], size_t length) + { + buffer_insert(buffer, position, input, length); + + if(position + length >= hash_block_size()) + { + hash(&buffer[0]); + input += (hash_block_size() - position); + length -= (hash_block_size() - position); + while(length >= hash_block_size()) + { + hash(input); + input += hash_block_size(); + length -= hash_block_size(); + } + copy_mem(&buffer[0], input, length); + position = 0; + } + position += length; + } + +/** +* Finalize a MD2 Hash +*/ +void MD2::final_result(byte output[]) + { + for(size_t i = position; i != hash_block_size(); ++i) + buffer[i] = static_cast(hash_block_size() - position); + + hash(&buffer[0]); + hash(&checksum[0]); + copy_mem(output, &X[0], output_length()); + clear(); + } + +/** +* Clear memory of sensitive data +*/ +void MD2::clear() + { + zeroise(X); + zeroise(checksum); + zeroise(buffer); + position = 0; + } + +} diff --git a/src/lib/hash/md2/md2.h b/src/lib/hash/md2/md2.h new file mode 100644 index 000000000..032d8a8e0 --- /dev/null +++ b/src/lib/hash/md2/md2.h @@ -0,0 +1,41 @@ +/* +* MD2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MD2_H__ +#define BOTAN_MD2_H__ + +#include + +namespace Botan { + +/** +* MD2 +*/ +class BOTAN_DLL MD2 : public HashFunction + { + public: + std::string name() const { return "MD2"; } + size_t output_length() const { return 16; } + size_t hash_block_size() const { return 16; } + HashFunction* clone() const { return new MD2; } + + void clear(); + + MD2() : X(48), checksum(16), buffer(16) + { clear(); } + private: + void add_data(const byte[], size_t); + void hash(const byte[]); + void final_result(byte[]); + + secure_vector X, checksum, buffer; + size_t position; + }; + +} + +#endif diff --git a/src/lib/hash/md4/info.txt b/src/lib/hash/md4/info.txt new file mode 100644 index 000000000..8894d4af3 --- /dev/null +++ b/src/lib/hash/md4/info.txt @@ -0,0 +1,5 @@ +define MD4 20131128 + + +mdx_hash + diff --git a/src/lib/hash/md4/md4.cpp b/src/lib/hash/md4/md4.cpp new file mode 100644 index 000000000..9b9ebab36 --- /dev/null +++ b/src/lib/hash/md4/md4.cpp @@ -0,0 +1,114 @@ +/* +* MD4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* MD4 FF Function +*/ +inline void FF(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S) + { + A += (D ^ (B & (C ^ D))) + M; + A = rotate_left(A, S); + } + +/* +* MD4 GG Function +*/ +inline void GG(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S) + { + A += ((B & C) | (D & (B | C))) + M + 0x5A827999; + A = rotate_left(A, S); + } + +/* +* MD4 HH Function +*/ +inline void HH(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S) + { + A += (B ^ C ^ D) + M + 0x6ED9EBA1; + A = rotate_left(A, S); + } + +} + +/* +* MD4 Compression Function +*/ +void MD4::compress_n(const byte input[], size_t blocks) + { + u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + FF(A,B,C,D,M[ 0], 3); FF(D,A,B,C,M[ 1], 7); + FF(C,D,A,B,M[ 2],11); FF(B,C,D,A,M[ 3],19); + FF(A,B,C,D,M[ 4], 3); FF(D,A,B,C,M[ 5], 7); + FF(C,D,A,B,M[ 6],11); FF(B,C,D,A,M[ 7],19); + FF(A,B,C,D,M[ 8], 3); FF(D,A,B,C,M[ 9], 7); + FF(C,D,A,B,M[10],11); FF(B,C,D,A,M[11],19); + FF(A,B,C,D,M[12], 3); FF(D,A,B,C,M[13], 7); + FF(C,D,A,B,M[14],11); FF(B,C,D,A,M[15],19); + + GG(A,B,C,D,M[ 0], 3); GG(D,A,B,C,M[ 4], 5); + GG(C,D,A,B,M[ 8], 9); GG(B,C,D,A,M[12],13); + GG(A,B,C,D,M[ 1], 3); GG(D,A,B,C,M[ 5], 5); + GG(C,D,A,B,M[ 9], 9); GG(B,C,D,A,M[13],13); + GG(A,B,C,D,M[ 2], 3); GG(D,A,B,C,M[ 6], 5); + GG(C,D,A,B,M[10], 9); GG(B,C,D,A,M[14],13); + GG(A,B,C,D,M[ 3], 3); GG(D,A,B,C,M[ 7], 5); + GG(C,D,A,B,M[11], 9); GG(B,C,D,A,M[15],13); + + HH(A,B,C,D,M[ 0], 3); HH(D,A,B,C,M[ 8], 9); + HH(C,D,A,B,M[ 4],11); HH(B,C,D,A,M[12],15); + HH(A,B,C,D,M[ 2], 3); HH(D,A,B,C,M[10], 9); + HH(C,D,A,B,M[ 6],11); HH(B,C,D,A,M[14],15); + HH(A,B,C,D,M[ 1], 3); HH(D,A,B,C,M[ 9], 9); + HH(C,D,A,B,M[ 5],11); HH(B,C,D,A,M[13],15); + HH(A,B,C,D,M[ 3], 3); HH(D,A,B,C,M[11], 9); + HH(C,D,A,B,M[ 7],11); HH(B,C,D,A,M[15],15); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void MD4::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void MD4::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + } + +} diff --git a/src/lib/hash/md4/md4.h b/src/lib/hash/md4/md4.h new file mode 100644 index 000000000..750be0fe7 --- /dev/null +++ b/src/lib/hash/md4/md4.h @@ -0,0 +1,46 @@ +/* +* MD4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MD4_H__ +#define BOTAN_MD4_H__ + +#include + +namespace Botan { + +/** +* MD4 +*/ +class BOTAN_DLL MD4 : public MDx_HashFunction + { + public: + std::string name() const { return "MD4"; } + size_t output_length() const { return 16; } + HashFunction* clone() const { return new MD4; } + + void clear(); + + MD4() : MDx_HashFunction(64, false, true), M(16), digest(4) + { clear(); } + protected: + void compress_n(const byte input[], size_t blocks); + void copy_out(byte[]); + + /** + * The message buffer, exposed for use by subclasses (x86 asm) + */ + secure_vector M; + + /** + * The digest value, exposed for use by subclasses (x86 asm) + */ + secure_vector digest; + }; + +} + +#endif diff --git a/src/lib/hash/md4_x86_32/info.txt b/src/lib/hash/md4_x86_32/info.txt new file mode 100644 index 000000000..fa7eef6cb --- /dev/null +++ b/src/lib/hash/md4_x86_32/info.txt @@ -0,0 +1,12 @@ +define MD4_X86_32 20131128 + +load_on asm_ok + + +x86_32 + + + +asm_x86_32 +md4 + diff --git a/src/lib/hash/md4_x86_32/md4_x86_32.cpp b/src/lib/hash/md4_x86_32/md4_x86_32.cpp new file mode 100644 index 000000000..ed3f72fc9 --- /dev/null +++ b/src/lib/hash/md4_x86_32/md4_x86_32.cpp @@ -0,0 +1,34 @@ +/* +* MD4 (x86-32) +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/** +* MD4 compression function in x86-32 asm +* @param digest the current digest +* @param input the input block +* @param M the message buffer +*/ +extern "C" void botan_md4_x86_32_compress(u32bit digest[4], + const byte input[64], + u32bit M[16]); + +/* +* MD4 Compression Function +*/ +void MD4_X86_32::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + botan_md4_x86_32_compress(&digest[0], input, &M[0]); + input += hash_block_size(); + } + } + +} diff --git a/src/lib/hash/md4_x86_32/md4_x86_32.h b/src/lib/hash/md4_x86_32/md4_x86_32.h new file mode 100644 index 000000000..a9f23e94f --- /dev/null +++ b/src/lib/hash/md4_x86_32/md4_x86_32.h @@ -0,0 +1,28 @@ +/* +* MD4 (x86-32) +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MD4_X86_32_H__ +#define BOTAN_MD4_X86_32_H__ + +#include + +namespace Botan { + +/** +* MD4 using x86 assembly +*/ +class BOTAN_DLL MD4_X86_32 : public MD4 + { + public: + HashFunction* clone() const { return new MD4_X86_32; } + private: + void compress_n(const byte[], size_t blocks); + }; + +} + +#endif diff --git a/src/lib/hash/md4_x86_32/md4_x86_32_imp.S b/src/lib/hash/md4_x86_32/md4_x86_32_imp.S new file mode 100644 index 000000000..192751166 --- /dev/null +++ b/src/lib/hash/md4_x86_32/md4_x86_32_imp.S @@ -0,0 +1,137 @@ +/* +* MD4 in x86-32 assembler +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +START_LISTING(md4_x86_32_imp.S) + +START_FUNCTION(botan_md4_x86_32_compress) + SPILL_REGS() + +#define PUSHED 4 + + ASSIGN(EBP, ARG(2)) /* input block */ + ASSIGN(EDI, ARG(3)) /* expanded words */ + + ZEROIZE(ESI) + +START_LOOP(.LOAD_INPUT) + ADD_IMM(ESI, 4) + + ASSIGN(EAX, ARRAY4(EBP, 0)) + ASSIGN(EBX, ARRAY4(EBP, 1)) + ASSIGN(ECX, ARRAY4(EBP, 2)) + ASSIGN(EDX, ARRAY4(EBP, 3)) + + ADD_IMM(EBP, 16) + + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-4), EAX) + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-3), EBX) + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-2), ECX) + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-1), EDX) +LOOP_UNTIL_EQ(ESI, 16, .LOAD_INPUT) + + ASSIGN(EBP, ARG(1)) + ASSIGN(EAX, ARRAY4(EBP, 0)) + ASSIGN(EBX, ARRAY4(EBP, 1)) + ASSIGN(ECX, ARRAY4(EBP, 2)) + ASSIGN(EDX, ARRAY4(EBP, 3)) + +#define MSG EDI +#define T1 ESI +#define T2 EBP + +#define FF(A, B, C, D, N, S) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, C) ; \ + XOR(T2, D) ; \ + AND(T2, B) ; \ + XOR(T2, D) ; \ + ADD(A, T1) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; + +#define GG(A, B, C, D, N, S) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, B) ; \ + OR(T2, C) ; \ + AND(T2, D) ; \ + ADD3_IMM(A, T1, 0x5A827999) ; \ + ASSIGN(T1, B) ; \ + AND(T1, C) ; \ + OR(T2, T1) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; + +#define HH(A, B, C, D, N, S) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, B) ; \ + XOR(T2, C) ; \ + XOR(T2, D) ; \ + ADD3_IMM(A, T1, 0x6ED9EBA1) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; + + FF(EAX,EBX,ECX,EDX, 0, 3); + FF(EDX,EAX,EBX,ECX, 1, 7); + FF(ECX,EDX,EAX,EBX, 2,11); + FF(EBX,ECX,EDX,EAX, 3,19); + FF(EAX,EBX,ECX,EDX, 4, 3); + FF(EDX,EAX,EBX,ECX, 5, 7); + FF(ECX,EDX,EAX,EBX, 6,11); + FF(EBX,ECX,EDX,EAX, 7,19); + FF(EAX,EBX,ECX,EDX, 8, 3); + FF(EDX,EAX,EBX,ECX, 9, 7); + FF(ECX,EDX,EAX,EBX,10,11); + FF(EBX,ECX,EDX,EAX,11,19); + FF(EAX,EBX,ECX,EDX,12, 3); + FF(EDX,EAX,EBX,ECX,13, 7); + FF(ECX,EDX,EAX,EBX,14,11); + FF(EBX,ECX,EDX,EAX,15,19); + + GG(EAX,EBX,ECX,EDX, 0, 3); + GG(EDX,EAX,EBX,ECX, 4, 5); + GG(ECX,EDX,EAX,EBX, 8, 9); + GG(EBX,ECX,EDX,EAX,12,13); + GG(EAX,EBX,ECX,EDX, 1, 3); + GG(EDX,EAX,EBX,ECX, 5, 5); + GG(ECX,EDX,EAX,EBX, 9, 9); + GG(EBX,ECX,EDX,EAX,13,13); + GG(EAX,EBX,ECX,EDX, 2, 3); + GG(EDX,EAX,EBX,ECX, 6, 5); + GG(ECX,EDX,EAX,EBX,10, 9); + GG(EBX,ECX,EDX,EAX,14,13); + GG(EAX,EBX,ECX,EDX, 3, 3); + GG(EDX,EAX,EBX,ECX, 7, 5); + GG(ECX,EDX,EAX,EBX,11, 9); + GG(EBX,ECX,EDX,EAX,15,13); + + HH(EAX,EBX,ECX,EDX, 0, 3); + HH(EDX,EAX,EBX,ECX, 8, 9); + HH(ECX,EDX,EAX,EBX, 4,11); + HH(EBX,ECX,EDX,EAX,12,15); + HH(EAX,EBX,ECX,EDX, 2, 3); + HH(EDX,EAX,EBX,ECX,10, 9); + HH(ECX,EDX,EAX,EBX, 6,11); + HH(EBX,ECX,EDX,EAX,14,15); + HH(EAX,EBX,ECX,EDX, 1, 3); + HH(EDX,EAX,EBX,ECX, 9, 9); + HH(ECX,EDX,EAX,EBX, 5,11); + HH(EBX,ECX,EDX,EAX,13,15); + HH(EAX,EBX,ECX,EDX, 3, 3); + HH(EDX,EAX,EBX,ECX,11, 9); + HH(ECX,EDX,EAX,EBX, 7,11); + HH(EBX,ECX,EDX,EAX,15,15); + + ASSIGN(EBP, ARG(1)) + ADD(ARRAY4(EBP, 0), EAX) + ADD(ARRAY4(EBP, 1), EBX) + ADD(ARRAY4(EBP, 2), ECX) + ADD(ARRAY4(EBP, 3), EDX) + + RESTORE_REGS() +END_FUNCTION(botan_md4_x86_32_compress) diff --git a/src/lib/hash/md5/info.txt b/src/lib/hash/md5/info.txt new file mode 100644 index 000000000..8bbf1c3e7 --- /dev/null +++ b/src/lib/hash/md5/info.txt @@ -0,0 +1,5 @@ +define MD5 20131128 + + +mdx_hash + diff --git a/src/lib/hash/md5/md5.cpp b/src/lib/hash/md5/md5.cpp new file mode 100644 index 000000000..948f4e73b --- /dev/null +++ b/src/lib/hash/md5/md5.cpp @@ -0,0 +1,136 @@ +/* +* MD5 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* MD5 FF Function +*/ +inline void FF(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (D ^ (B & (C ^ D))) + msg + magic; + A = rotate_left(A, S) + B; + } + +/* +* MD5 GG Function +*/ +inline void GG(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (C ^ (D & (B ^ C))) + msg + magic; + A = rotate_left(A, S) + B; + } + +/* +* MD5 HH Function +*/ +inline void HH(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (B ^ C ^ D) + msg + magic; + A = rotate_left(A, S) + B; + } + +/* +* MD5 II Function +*/ +inline void II(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (C ^ (B | ~D)) + msg + magic; + A = rotate_left(A, S) + B; + } + +} + +/* +* MD5 Compression Function +*/ +void MD5::compress_n(const byte input[], size_t blocks) + { + u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + FF(A,B,C,D,M[ 0], 7,0xD76AA478); FF(D,A,B,C,M[ 1],12,0xE8C7B756); + FF(C,D,A,B,M[ 2],17,0x242070DB); FF(B,C,D,A,M[ 3],22,0xC1BDCEEE); + FF(A,B,C,D,M[ 4], 7,0xF57C0FAF); FF(D,A,B,C,M[ 5],12,0x4787C62A); + FF(C,D,A,B,M[ 6],17,0xA8304613); FF(B,C,D,A,M[ 7],22,0xFD469501); + FF(A,B,C,D,M[ 8], 7,0x698098D8); FF(D,A,B,C,M[ 9],12,0x8B44F7AF); + FF(C,D,A,B,M[10],17,0xFFFF5BB1); FF(B,C,D,A,M[11],22,0x895CD7BE); + FF(A,B,C,D,M[12], 7,0x6B901122); FF(D,A,B,C,M[13],12,0xFD987193); + FF(C,D,A,B,M[14],17,0xA679438E); FF(B,C,D,A,M[15],22,0x49B40821); + + GG(A,B,C,D,M[ 1], 5,0xF61E2562); GG(D,A,B,C,M[ 6], 9,0xC040B340); + GG(C,D,A,B,M[11],14,0x265E5A51); GG(B,C,D,A,M[ 0],20,0xE9B6C7AA); + GG(A,B,C,D,M[ 5], 5,0xD62F105D); GG(D,A,B,C,M[10], 9,0x02441453); + GG(C,D,A,B,M[15],14,0xD8A1E681); GG(B,C,D,A,M[ 4],20,0xE7D3FBC8); + GG(A,B,C,D,M[ 9], 5,0x21E1CDE6); GG(D,A,B,C,M[14], 9,0xC33707D6); + GG(C,D,A,B,M[ 3],14,0xF4D50D87); GG(B,C,D,A,M[ 8],20,0x455A14ED); + GG(A,B,C,D,M[13], 5,0xA9E3E905); GG(D,A,B,C,M[ 2], 9,0xFCEFA3F8); + GG(C,D,A,B,M[ 7],14,0x676F02D9); GG(B,C,D,A,M[12],20,0x8D2A4C8A); + + HH(A,B,C,D,M[ 5], 4,0xFFFA3942); HH(D,A,B,C,M[ 8],11,0x8771F681); + HH(C,D,A,B,M[11],16,0x6D9D6122); HH(B,C,D,A,M[14],23,0xFDE5380C); + HH(A,B,C,D,M[ 1], 4,0xA4BEEA44); HH(D,A,B,C,M[ 4],11,0x4BDECFA9); + HH(C,D,A,B,M[ 7],16,0xF6BB4B60); HH(B,C,D,A,M[10],23,0xBEBFBC70); + HH(A,B,C,D,M[13], 4,0x289B7EC6); HH(D,A,B,C,M[ 0],11,0xEAA127FA); + HH(C,D,A,B,M[ 3],16,0xD4EF3085); HH(B,C,D,A,M[ 6],23,0x04881D05); + HH(A,B,C,D,M[ 9], 4,0xD9D4D039); HH(D,A,B,C,M[12],11,0xE6DB99E5); + HH(C,D,A,B,M[15],16,0x1FA27CF8); HH(B,C,D,A,M[ 2],23,0xC4AC5665); + + II(A,B,C,D,M[ 0], 6,0xF4292244); II(D,A,B,C,M[ 7],10,0x432AFF97); + II(C,D,A,B,M[14],15,0xAB9423A7); II(B,C,D,A,M[ 5],21,0xFC93A039); + II(A,B,C,D,M[12], 6,0x655B59C3); II(D,A,B,C,M[ 3],10,0x8F0CCC92); + II(C,D,A,B,M[10],15,0xFFEFF47D); II(B,C,D,A,M[ 1],21,0x85845DD1); + II(A,B,C,D,M[ 8], 6,0x6FA87E4F); II(D,A,B,C,M[15],10,0xFE2CE6E0); + II(C,D,A,B,M[ 6],15,0xA3014314); II(B,C,D,A,M[13],21,0x4E0811A1); + II(A,B,C,D,M[ 4], 6,0xF7537E82); II(D,A,B,C,M[11],10,0xBD3AF235); + II(C,D,A,B,M[ 2],15,0x2AD7D2BB); II(B,C,D,A,M[ 9],21,0xEB86D391); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void MD5::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void MD5::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + } + +} diff --git a/src/lib/hash/md5/md5.h b/src/lib/hash/md5/md5.h new file mode 100644 index 000000000..bc90df0af --- /dev/null +++ b/src/lib/hash/md5/md5.h @@ -0,0 +1,46 @@ +/* +* MD5 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MD5_H__ +#define BOTAN_MD5_H__ + +#include + +namespace Botan { + +/** +* MD5 +*/ +class BOTAN_DLL MD5 : public MDx_HashFunction + { + public: + std::string name() const { return "MD5"; } + size_t output_length() const { return 16; } + HashFunction* clone() const { return new MD5; } + + void clear(); + + MD5() : MDx_HashFunction(64, false, true), M(16), digest(4) + { clear(); } + protected: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + /** + * The message buffer, exposed for use by subclasses (x86 asm) + */ + secure_vector M; + + /** + * The digest value, exposed for use by subclasses (x86 asm) + */ + secure_vector digest; + }; + +} + +#endif diff --git a/src/lib/hash/md5_x86_32/info.txt b/src/lib/hash/md5_x86_32/info.txt new file mode 100644 index 000000000..769ee8389 --- /dev/null +++ b/src/lib/hash/md5_x86_32/info.txt @@ -0,0 +1,12 @@ +define MD5_X86_32 20131128 + +load_on asm_ok + + +x86_32 + + + +asm_x86_32 +md5 + diff --git a/src/lib/hash/md5_x86_32/md5_x86_32.cpp b/src/lib/hash/md5_x86_32/md5_x86_32.cpp new file mode 100644 index 000000000..73071ac18 --- /dev/null +++ b/src/lib/hash/md5_x86_32/md5_x86_32.cpp @@ -0,0 +1,31 @@ +/* +* MD5 (x86-32) +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +extern "C" +void botan_md5_x86_32_compress(u32bit[4], const byte[64], u32bit[16]); + +} + +/* +* MD5 Compression Function +*/ +void MD5_X86_32::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + botan_md5_x86_32_compress(&digest[0], input, &M[0]); + input += hash_block_size(); + } + } + +} diff --git a/src/lib/hash/md5_x86_32/md5_x86_32.h b/src/lib/hash/md5_x86_32/md5_x86_32.h new file mode 100644 index 000000000..0150249ae --- /dev/null +++ b/src/lib/hash/md5_x86_32/md5_x86_32.h @@ -0,0 +1,28 @@ +/* +* MD5 (x86-32) +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MD5_X86_32_H__ +#define BOTAN_MD5_X86_32_H__ + +#include + +namespace Botan { + +/** +* MD5 in x86 assembly +*/ +class BOTAN_DLL MD5_X86_32 : public MD5 + { + public: + HashFunction* clone() const { return new MD5_X86_32; } + private: + void compress_n(const byte[], size_t blocks); + }; + +} + +#endif diff --git a/src/lib/hash/md5_x86_32/md5_x86_32_imp.S b/src/lib/hash/md5_x86_32/md5_x86_32_imp.S new file mode 100644 index 000000000..f41aaccbf --- /dev/null +++ b/src/lib/hash/md5_x86_32/md5_x86_32_imp.S @@ -0,0 +1,166 @@ +/* +* MD5 in x86-32 assembler +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +START_LISTING(md5_x86_32.S) + +START_FUNCTION(botan_md5_x86_32_compress) + SPILL_REGS() + +#define PUSHED 4 + + ASSIGN(EBP, ARG(2)) /* input block */ + ASSIGN(EDI, ARG(3)) /* expanded words */ + + ZEROIZE(ESI) + +START_LOOP(.LOAD_INPUT) + ADD_IMM(ESI, 4) + + ASSIGN(EAX, ARRAY4(EBP, 0)) + ASSIGN(EBX, ARRAY4(EBP, 1)) + ASSIGN(ECX, ARRAY4(EBP, 2)) + ASSIGN(EDX, ARRAY4(EBP, 3)) + + ADD_IMM(EBP, 16) + + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-4), EAX) + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-3), EBX) + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-2), ECX) + ASSIGN(ARRAY4_INDIRECT(EDI,ESI,-1), EDX) +LOOP_UNTIL_EQ(ESI, 16, .LOAD_INPUT) + + ASSIGN(EBP, ARG(1)) + ASSIGN(EAX, ARRAY4(EBP, 0)) + ASSIGN(EBX, ARRAY4(EBP, 1)) + ASSIGN(ECX, ARRAY4(EBP, 2)) + ASSIGN(EDX, ARRAY4(EBP, 3)) + +#define MSG EDI +#define T1 ESI +#define T2 EBP + +#define FF(A, B, C, D, N, S, MAGIC) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, C) ; \ + XOR(T2, D) ; \ + AND(T2, B) ; \ + XOR(T2, D) ; \ + ADD3_IMM(A, T1, MAGIC) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; \ + ADD(A, B) ; + +#define GG(A, B, C, D, N, S, MAGIC) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, B) ; \ + XOR(T2, C) ; \ + AND(T2, D) ; \ + XOR(T2, C) ; \ + ADD3_IMM(A, T1, MAGIC) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; \ + ADD(A, B) ; + +#define HH(A, B, C, D, N, S, MAGIC) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, B) ; \ + XOR(T2, C) ; \ + XOR(T2, D) ; \ + ADD3_IMM(A, T1, MAGIC) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; \ + ADD(A, B) ; + +#define II(A, B, C, D, N, S, MAGIC) \ + ASSIGN(T1, ARRAY4(MSG, N)) ; \ + ASSIGN(T2, D) ; \ + NOT(T2) ; \ + OR(T2, B) ; \ + XOR(T2, C) ; \ + ADD3_IMM(A, T1, MAGIC) ; \ + ADD(A, T2) ; \ + ROTL_IMM(A, S) ; \ + ADD(A, B) ; + + FF(EAX,EBX,ECX,EDX, 0, 7,0xD76AA478); + FF(EDX,EAX,EBX,ECX, 1,12,0xE8C7B756); + FF(ECX,EDX,EAX,EBX, 2,17,0x242070DB); + FF(EBX,ECX,EDX,EAX, 3,22,0xC1BDCEEE); + FF(EAX,EBX,ECX,EDX, 4, 7,0xF57C0FAF); + FF(EDX,EAX,EBX,ECX, 5,12,0x4787C62A); + FF(ECX,EDX,EAX,EBX, 6,17,0xA8304613); + FF(EBX,ECX,EDX,EAX, 7,22,0xFD469501); + FF(EAX,EBX,ECX,EDX, 8, 7,0x698098D8); + FF(EDX,EAX,EBX,ECX, 9,12,0x8B44F7AF); + FF(ECX,EDX,EAX,EBX,10,17,0xFFFF5BB1); + FF(EBX,ECX,EDX,EAX,11,22,0x895CD7BE); + FF(EAX,EBX,ECX,EDX,12, 7,0x6B901122); + FF(EDX,EAX,EBX,ECX,13,12,0xFD987193); + FF(ECX,EDX,EAX,EBX,14,17,0xA679438E); + FF(EBX,ECX,EDX,EAX,15,22,0x49B40821); + + GG(EAX,EBX,ECX,EDX, 1, 5,0xF61E2562); + GG(EDX,EAX,EBX,ECX, 6, 9,0xC040B340); + GG(ECX,EDX,EAX,EBX,11,14,0x265E5A51); + GG(EBX,ECX,EDX,EAX, 0,20,0xE9B6C7AA); + GG(EAX,EBX,ECX,EDX, 5, 5,0xD62F105D); + GG(EDX,EAX,EBX,ECX,10, 9,0x02441453); + GG(ECX,EDX,EAX,EBX,15,14,0xD8A1E681); + GG(EBX,ECX,EDX,EAX, 4,20,0xE7D3FBC8); + GG(EAX,EBX,ECX,EDX, 9, 5,0x21E1CDE6); + GG(EDX,EAX,EBX,ECX,14, 9,0xC33707D6); + GG(ECX,EDX,EAX,EBX, 3,14,0xF4D50D87); + GG(EBX,ECX,EDX,EAX, 8,20,0x455A14ED); + GG(EAX,EBX,ECX,EDX,13, 5,0xA9E3E905); + GG(EDX,EAX,EBX,ECX, 2, 9,0xFCEFA3F8); + GG(ECX,EDX,EAX,EBX, 7,14,0x676F02D9); + GG(EBX,ECX,EDX,EAX,12,20,0x8D2A4C8A); + + HH(EAX,EBX,ECX,EDX, 5, 4,0xFFFA3942); + HH(EDX,EAX,EBX,ECX, 8,11,0x8771F681); + HH(ECX,EDX,EAX,EBX,11,16,0x6D9D6122); + HH(EBX,ECX,EDX,EAX,14,23,0xFDE5380C); + HH(EAX,EBX,ECX,EDX, 1, 4,0xA4BEEA44); + HH(EDX,EAX,EBX,ECX, 4,11,0x4BDECFA9); + HH(ECX,EDX,EAX,EBX, 7,16,0xF6BB4B60); + HH(EBX,ECX,EDX,EAX,10,23,0xBEBFBC70); + HH(EAX,EBX,ECX,EDX,13, 4,0x289B7EC6); + HH(EDX,EAX,EBX,ECX, 0,11,0xEAA127FA); + HH(ECX,EDX,EAX,EBX, 3,16,0xD4EF3085); + HH(EBX,ECX,EDX,EAX, 6,23,0x04881D05); + HH(EAX,EBX,ECX,EDX, 9, 4,0xD9D4D039); + HH(EDX,EAX,EBX,ECX,12,11,0xE6DB99E5); + HH(ECX,EDX,EAX,EBX,15,16,0x1FA27CF8); + HH(EBX,ECX,EDX,EAX, 2,23,0xC4AC5665); + + II(EAX,EBX,ECX,EDX, 0, 6,0xF4292244); + II(EDX,EAX,EBX,ECX, 7,10,0x432AFF97); + II(ECX,EDX,EAX,EBX,14,15,0xAB9423A7); + II(EBX,ECX,EDX,EAX, 5,21,0xFC93A039); + II(EAX,EBX,ECX,EDX,12, 6,0x655B59C3); + II(EDX,EAX,EBX,ECX, 3,10,0x8F0CCC92); + II(ECX,EDX,EAX,EBX,10,15,0xFFEFF47D); + II(EBX,ECX,EDX,EAX, 1,21,0x85845DD1); + II(EAX,EBX,ECX,EDX, 8, 6,0x6FA87E4F); + II(EDX,EAX,EBX,ECX,15,10,0xFE2CE6E0); + II(ECX,EDX,EAX,EBX, 6,15,0xA3014314); + II(EBX,ECX,EDX,EAX,13,21,0x4E0811A1); + II(EAX,EBX,ECX,EDX, 4, 6,0xF7537E82); + II(EDX,EAX,EBX,ECX,11,10,0xBD3AF235); + II(ECX,EDX,EAX,EBX, 2,15,0x2AD7D2BB); + II(EBX,ECX,EDX,EAX, 9,21,0xEB86D391); + + ASSIGN(EBP, ARG(1)) + ADD(ARRAY4(EBP, 0), EAX) + ADD(ARRAY4(EBP, 1), EBX) + ADD(ARRAY4(EBP, 2), ECX) + ADD(ARRAY4(EBP, 3), EDX) + + RESTORE_REGS() +END_FUNCTION(botan_md5_x86_32_compress) diff --git a/src/lib/hash/mdx_hash/info.txt b/src/lib/hash/mdx_hash/info.txt new file mode 100644 index 000000000..d9a24c621 --- /dev/null +++ b/src/lib/hash/mdx_hash/info.txt @@ -0,0 +1,3 @@ +define MDX_HASH_FUNCTION 20131128 + +load_on dep diff --git a/src/lib/hash/mdx_hash/mdx_hash.cpp b/src/lib/hash/mdx_hash/mdx_hash.cpp new file mode 100644 index 000000000..81042c1fa --- /dev/null +++ b/src/lib/hash/mdx_hash/mdx_hash.cpp @@ -0,0 +1,108 @@ +/* +* Merkle-Damgard Hash Function +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* MDx_HashFunction Constructor +*/ +MDx_HashFunction::MDx_HashFunction(size_t block_len, + bool byte_end, + bool bit_end, + size_t cnt_size) : + buffer(block_len), + BIG_BYTE_ENDIAN(byte_end), + BIG_BIT_ENDIAN(bit_end), + COUNT_SIZE(cnt_size) + { + count = position = 0; + } + +/* +* Clear memory of sensitive data +*/ +void MDx_HashFunction::clear() + { + zeroise(buffer); + count = position = 0; + } + +/* +* Update the hash +*/ +void MDx_HashFunction::add_data(const byte input[], size_t length) + { + count += length; + + if(position) + { + buffer_insert(buffer, position, input, length); + + if(position + length >= buffer.size()) + { + compress_n(&buffer[0], 1); + input += (buffer.size() - position); + length -= (buffer.size() - position); + position = 0; + } + } + + const size_t full_blocks = length / buffer.size(); + const size_t remaining = length % buffer.size(); + + if(full_blocks) + compress_n(input, full_blocks); + + buffer_insert(buffer, position, input + full_blocks * buffer.size(), remaining); + position += remaining; + } + +/* +* Finalize a hash +*/ +void MDx_HashFunction::final_result(byte output[]) + { + buffer[position] = (BIG_BIT_ENDIAN ? 0x80 : 0x01); + for(size_t i = position+1; i != buffer.size(); ++i) + buffer[i] = 0; + + if(position >= buffer.size() - COUNT_SIZE) + { + compress_n(&buffer[0], 1); + zeroise(buffer); + } + + write_count(&buffer[buffer.size() - COUNT_SIZE]); + + compress_n(&buffer[0], 1); + copy_out(output); + clear(); + } + +/* +* Write the count bits to the buffer +*/ +void MDx_HashFunction::write_count(byte out[]) + { + if(COUNT_SIZE < 8) + throw Invalid_State("MDx_HashFunction::write_count: COUNT_SIZE < 8"); + if(COUNT_SIZE >= output_length() || COUNT_SIZE >= hash_block_size()) + throw Invalid_Argument("MDx_HashFunction: COUNT_SIZE is too big"); + + const u64bit bit_count = count * 8; + + if(BIG_BYTE_ENDIAN) + store_be(bit_count, out + COUNT_SIZE - 8); + else + store_le(bit_count, out + COUNT_SIZE - 8); + } + +} diff --git a/src/lib/hash/mdx_hash/mdx_hash.h b/src/lib/hash/mdx_hash/mdx_hash.h new file mode 100644 index 000000000..14d3c27a0 --- /dev/null +++ b/src/lib/hash/mdx_hash/mdx_hash.h @@ -0,0 +1,68 @@ +/* +* MDx Hash Function +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MDX_BASE_H__ +#define BOTAN_MDX_BASE_H__ + +#include + +namespace Botan { + +/** +* MDx Hash Function Base Class +*/ +class BOTAN_DLL MDx_HashFunction : public HashFunction + { + public: + /** + * @param block_length is the number of bytes per block + * @param big_byte_endian specifies if the hash uses big-endian bytes + * @param big_bit_endian specifies if the hash uses big-endian bits + * @param counter_size specifies the size of the counter var in bytes + */ + MDx_HashFunction(size_t block_length, + bool big_byte_endian, + bool big_bit_endian, + size_t counter_size = 8); + + size_t hash_block_size() const { return buffer.size(); } + protected: + void add_data(const byte input[], size_t length); + void final_result(byte output[]); + + /** + * Run the hash's compression function over a set of blocks + * @param blocks the input + * @param block_n the number of blocks + */ + virtual void compress_n(const byte blocks[], size_t block_n) = 0; + + void clear(); + + /** + * Copy the output to the buffer + * @param buffer to put the output into + */ + virtual void copy_out(byte buffer[]) = 0; + + /** + * Write the count, if used, to this spot + * @param out where to write the counter to + */ + virtual void write_count(byte out[]); + private: + secure_vector buffer; + u64bit count; + size_t position; + + const bool BIG_BYTE_ENDIAN, BIG_BIT_ENDIAN; + const size_t COUNT_SIZE; + }; + +} + +#endif diff --git a/src/lib/hash/par_hash/info.txt b/src/lib/hash/par_hash/info.txt new file mode 100644 index 000000000..4f559b545 --- /dev/null +++ b/src/lib/hash/par_hash/info.txt @@ -0,0 +1 @@ +define PARALLEL_HASH 20131128 diff --git a/src/lib/hash/par_hash/par_hash.cpp b/src/lib/hash/par_hash/par_hash.cpp new file mode 100644 index 000000000..df47780ef --- /dev/null +++ b/src/lib/hash/par_hash/par_hash.cpp @@ -0,0 +1,100 @@ +/* +* Parallel +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Update the hash +*/ +void Parallel::add_data(const byte input[], size_t length) + { + for(auto hash : hashes) + hash->update(input, length); + } + +/* +* Finalize the hash +*/ +void Parallel::final_result(byte out[]) + { + u32bit offset = 0; + + for(auto hash : hashes) + { + hash->final(out + offset); + offset += hash->output_length(); + } + } + +/* +* Return output size +*/ +size_t Parallel::output_length() const + { + size_t sum = 0; + + for(auto hash : hashes) + sum += hash->output_length(); + return sum; + } + +/* +* Return the name of this type +*/ +std::string Parallel::name() const + { + std::vector names; + + for(auto hash : hashes) + names.push_back(hash->name()); + + return "Parallel(" + string_join(names, ',') + ")"; + } + +/* +* Return a clone of this object +*/ +HashFunction* Parallel::clone() const + { + std::vector hash_copies; + + for(auto hash : hashes) + hash_copies.push_back(hash->clone()); + + return new Parallel(hash_copies); + } + +/* +* Clear memory of sensitive data +*/ +void Parallel::clear() + { + for(auto hash : hashes) + hash->clear(); + } + +/* +* Parallel Constructor +*/ +Parallel::Parallel(const std::vector& hash_in) : + hashes(hash_in) + { + } + +/* +* Parallel Destructor +*/ +Parallel::~Parallel() + { + for(auto hash : hashes) + delete hash; + } + +} diff --git a/src/lib/hash/par_hash/par_hash.h b/src/lib/hash/par_hash/par_hash.h new file mode 100644 index 000000000..4f5395c23 --- /dev/null +++ b/src/lib/hash/par_hash/par_hash.h @@ -0,0 +1,41 @@ +/* +* Parallel Hash +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PARALLEL_HASH_H__ +#define BOTAN_PARALLEL_HASH_H__ + +#include +#include + +namespace Botan { + +/** +* Parallel Hashes +*/ +class BOTAN_DLL Parallel : public HashFunction + { + public: + void clear(); + std::string name() const; + HashFunction* clone() const; + + size_t output_length() const; + + /** + * @param hashes a set of hashes to compute in parallel + */ + Parallel(const std::vector& hashes); + ~Parallel(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + std::vector hashes; + }; + +} + +#endif diff --git a/src/lib/hash/rmd128/info.txt b/src/lib/hash/rmd128/info.txt new file mode 100644 index 000000000..7d2a4eacd --- /dev/null +++ b/src/lib/hash/rmd128/info.txt @@ -0,0 +1,5 @@ +define RIPEMD_128 20131128 + + +mdx_hash + diff --git a/src/lib/hash/rmd128/rmd128.cpp b/src/lib/hash/rmd128/rmd128.cpp new file mode 100644 index 000000000..cab4adf8b --- /dev/null +++ b/src/lib/hash/rmd128/rmd128.cpp @@ -0,0 +1,176 @@ +/* +* RIPEMD-128 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace RIPEMD_128_F { + +/* +* RIPEMD-128 F1 Function +*/ +inline void F1(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift) + { + A += (B ^ C ^ D) + msg; + A = rotate_left(A, shift); + } + +/* +* RIPEMD-128 F2 Function +*/ +inline void F2(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B & (C ^ D))) + msg + magic; + A = rotate_left(A, shift); + } + +/* +* RIPEMD-128 F3 Function +*/ +inline void F3(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B | ~C)) + msg + magic; + A = rotate_left(A, shift); + } + +/* +* RIPEMD-128 F4 Function +*/ +inline void F4(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift, u32bit magic) + { + A += (C ^ (D & (B ^ C))) + msg + magic; + A = rotate_left(A, shift); + } + +} + +/* +* RIPEMD-128 Compression Function +*/ +void RIPEMD_128::compress_n(const byte input[], size_t blocks) + { + using namespace RIPEMD_128_F; + + const u32bit MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1, + MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0x50A28BE6, + MAGIC6 = 0x5C4DD124, MAGIC7 = 0x6D703EF3; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + u32bit A1 = digest[0], A2 = A1, B1 = digest[1], B2 = B1, + C1 = digest[2], C2 = C1, D1 = digest[3], D2 = D1; + + F1(A1,B1,C1,D1,M[ 0],11 ); F4(A2,B2,C2,D2,M[ 5], 8,MAGIC5); + F1(D1,A1,B1,C1,M[ 1],14 ); F4(D2,A2,B2,C2,M[14], 9,MAGIC5); + F1(C1,D1,A1,B1,M[ 2],15 ); F4(C2,D2,A2,B2,M[ 7], 9,MAGIC5); + F1(B1,C1,D1,A1,M[ 3],12 ); F4(B2,C2,D2,A2,M[ 0],11,MAGIC5); + F1(A1,B1,C1,D1,M[ 4], 5 ); F4(A2,B2,C2,D2,M[ 9],13,MAGIC5); + F1(D1,A1,B1,C1,M[ 5], 8 ); F4(D2,A2,B2,C2,M[ 2],15,MAGIC5); + F1(C1,D1,A1,B1,M[ 6], 7 ); F4(C2,D2,A2,B2,M[11],15,MAGIC5); + F1(B1,C1,D1,A1,M[ 7], 9 ); F4(B2,C2,D2,A2,M[ 4], 5,MAGIC5); + F1(A1,B1,C1,D1,M[ 8],11 ); F4(A2,B2,C2,D2,M[13], 7,MAGIC5); + F1(D1,A1,B1,C1,M[ 9],13 ); F4(D2,A2,B2,C2,M[ 6], 7,MAGIC5); + F1(C1,D1,A1,B1,M[10],14 ); F4(C2,D2,A2,B2,M[15], 8,MAGIC5); + F1(B1,C1,D1,A1,M[11],15 ); F4(B2,C2,D2,A2,M[ 8],11,MAGIC5); + F1(A1,B1,C1,D1,M[12], 6 ); F4(A2,B2,C2,D2,M[ 1],14,MAGIC5); + F1(D1,A1,B1,C1,M[13], 7 ); F4(D2,A2,B2,C2,M[10],14,MAGIC5); + F1(C1,D1,A1,B1,M[14], 9 ); F4(C2,D2,A2,B2,M[ 3],12,MAGIC5); + F1(B1,C1,D1,A1,M[15], 8 ); F4(B2,C2,D2,A2,M[12], 6,MAGIC5); + + F2(A1,B1,C1,D1,M[ 7], 7,MAGIC2); F3(A2,B2,C2,D2,M[ 6], 9,MAGIC6); + F2(D1,A1,B1,C1,M[ 4], 6,MAGIC2); F3(D2,A2,B2,C2,M[11],13,MAGIC6); + F2(C1,D1,A1,B1,M[13], 8,MAGIC2); F3(C2,D2,A2,B2,M[ 3],15,MAGIC6); + F2(B1,C1,D1,A1,M[ 1],13,MAGIC2); F3(B2,C2,D2,A2,M[ 7], 7,MAGIC6); + F2(A1,B1,C1,D1,M[10],11,MAGIC2); F3(A2,B2,C2,D2,M[ 0],12,MAGIC6); + F2(D1,A1,B1,C1,M[ 6], 9,MAGIC2); F3(D2,A2,B2,C2,M[13], 8,MAGIC6); + F2(C1,D1,A1,B1,M[15], 7,MAGIC2); F3(C2,D2,A2,B2,M[ 5], 9,MAGIC6); + F2(B1,C1,D1,A1,M[ 3],15,MAGIC2); F3(B2,C2,D2,A2,M[10],11,MAGIC6); + F2(A1,B1,C1,D1,M[12], 7,MAGIC2); F3(A2,B2,C2,D2,M[14], 7,MAGIC6); + F2(D1,A1,B1,C1,M[ 0],12,MAGIC2); F3(D2,A2,B2,C2,M[15], 7,MAGIC6); + F2(C1,D1,A1,B1,M[ 9],15,MAGIC2); F3(C2,D2,A2,B2,M[ 8],12,MAGIC6); + F2(B1,C1,D1,A1,M[ 5], 9,MAGIC2); F3(B2,C2,D2,A2,M[12], 7,MAGIC6); + F2(A1,B1,C1,D1,M[ 2],11,MAGIC2); F3(A2,B2,C2,D2,M[ 4], 6,MAGIC6); + F2(D1,A1,B1,C1,M[14], 7,MAGIC2); F3(D2,A2,B2,C2,M[ 9],15,MAGIC6); + F2(C1,D1,A1,B1,M[11],13,MAGIC2); F3(C2,D2,A2,B2,M[ 1],13,MAGIC6); + F2(B1,C1,D1,A1,M[ 8],12,MAGIC2); F3(B2,C2,D2,A2,M[ 2],11,MAGIC6); + + F3(A1,B1,C1,D1,M[ 3],11,MAGIC3); F2(A2,B2,C2,D2,M[15], 9,MAGIC7); + F3(D1,A1,B1,C1,M[10],13,MAGIC3); F2(D2,A2,B2,C2,M[ 5], 7,MAGIC7); + F3(C1,D1,A1,B1,M[14], 6,MAGIC3); F2(C2,D2,A2,B2,M[ 1],15,MAGIC7); + F3(B1,C1,D1,A1,M[ 4], 7,MAGIC3); F2(B2,C2,D2,A2,M[ 3],11,MAGIC7); + F3(A1,B1,C1,D1,M[ 9],14,MAGIC3); F2(A2,B2,C2,D2,M[ 7], 8,MAGIC7); + F3(D1,A1,B1,C1,M[15], 9,MAGIC3); F2(D2,A2,B2,C2,M[14], 6,MAGIC7); + F3(C1,D1,A1,B1,M[ 8],13,MAGIC3); F2(C2,D2,A2,B2,M[ 6], 6,MAGIC7); + F3(B1,C1,D1,A1,M[ 1],15,MAGIC3); F2(B2,C2,D2,A2,M[ 9],14,MAGIC7); + F3(A1,B1,C1,D1,M[ 2],14,MAGIC3); F2(A2,B2,C2,D2,M[11],12,MAGIC7); + F3(D1,A1,B1,C1,M[ 7], 8,MAGIC3); F2(D2,A2,B2,C2,M[ 8],13,MAGIC7); + F3(C1,D1,A1,B1,M[ 0],13,MAGIC3); F2(C2,D2,A2,B2,M[12], 5,MAGIC7); + F3(B1,C1,D1,A1,M[ 6], 6,MAGIC3); F2(B2,C2,D2,A2,M[ 2],14,MAGIC7); + F3(A1,B1,C1,D1,M[13], 5,MAGIC3); F2(A2,B2,C2,D2,M[10],13,MAGIC7); + F3(D1,A1,B1,C1,M[11],12,MAGIC3); F2(D2,A2,B2,C2,M[ 0],13,MAGIC7); + F3(C1,D1,A1,B1,M[ 5], 7,MAGIC3); F2(C2,D2,A2,B2,M[ 4], 7,MAGIC7); + F3(B1,C1,D1,A1,M[12], 5,MAGIC3); F2(B2,C2,D2,A2,M[13], 5,MAGIC7); + + F4(A1,B1,C1,D1,M[ 1],11,MAGIC4); F1(A2,B2,C2,D2,M[ 8],15 ); + F4(D1,A1,B1,C1,M[ 9],12,MAGIC4); F1(D2,A2,B2,C2,M[ 6], 5 ); + F4(C1,D1,A1,B1,M[11],14,MAGIC4); F1(C2,D2,A2,B2,M[ 4], 8 ); + F4(B1,C1,D1,A1,M[10],15,MAGIC4); F1(B2,C2,D2,A2,M[ 1],11 ); + F4(A1,B1,C1,D1,M[ 0],14,MAGIC4); F1(A2,B2,C2,D2,M[ 3],14 ); + F4(D1,A1,B1,C1,M[ 8],15,MAGIC4); F1(D2,A2,B2,C2,M[11],14 ); + F4(C1,D1,A1,B1,M[12], 9,MAGIC4); F1(C2,D2,A2,B2,M[15], 6 ); + F4(B1,C1,D1,A1,M[ 4], 8,MAGIC4); F1(B2,C2,D2,A2,M[ 0],14 ); + F4(A1,B1,C1,D1,M[13], 9,MAGIC4); F1(A2,B2,C2,D2,M[ 5], 6 ); + F4(D1,A1,B1,C1,M[ 3],14,MAGIC4); F1(D2,A2,B2,C2,M[12], 9 ); + F4(C1,D1,A1,B1,M[ 7], 5,MAGIC4); F1(C2,D2,A2,B2,M[ 2],12 ); + F4(B1,C1,D1,A1,M[15], 6,MAGIC4); F1(B2,C2,D2,A2,M[13], 9 ); + F4(A1,B1,C1,D1,M[14], 8,MAGIC4); F1(A2,B2,C2,D2,M[ 9],12 ); + F4(D1,A1,B1,C1,M[ 5], 6,MAGIC4); F1(D2,A2,B2,C2,M[ 7], 5 ); + F4(C1,D1,A1,B1,M[ 6], 5,MAGIC4); F1(C2,D2,A2,B2,M[10],15 ); + F4(B1,C1,D1,A1,M[ 2],12,MAGIC4); F1(B2,C2,D2,A2,M[14], 8 ); + + D2 = digest[1] + C1 + D2; + digest[1] = digest[2] + D1 + A2; + digest[2] = digest[3] + A1 + B2; + digest[3] = digest[0] + B1 + C2; + digest[0] = D2; + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void RIPEMD_128::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void RIPEMD_128::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + } + +} diff --git a/src/lib/hash/rmd128/rmd128.h b/src/lib/hash/rmd128/rmd128.h new file mode 100644 index 000000000..e37666a27 --- /dev/null +++ b/src/lib/hash/rmd128/rmd128.h @@ -0,0 +1,38 @@ +/* +* RIPEMD-128 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RIPEMD_128_H__ +#define BOTAN_RIPEMD_128_H__ + +#include + +namespace Botan { + +/** +* RIPEMD-128 +*/ +class BOTAN_DLL RIPEMD_128 : public MDx_HashFunction + { + public: + std::string name() const { return "RIPEMD-128"; } + size_t output_length() const { return 16; } + HashFunction* clone() const { return new RIPEMD_128; } + + void clear(); + + RIPEMD_128() : MDx_HashFunction(64, false, true), M(16), digest(4) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector M, digest; + }; + +} + +#endif diff --git a/src/lib/hash/rmd160/info.txt b/src/lib/hash/rmd160/info.txt new file mode 100644 index 000000000..4e1451bb6 --- /dev/null +++ b/src/lib/hash/rmd160/info.txt @@ -0,0 +1,5 @@ +define RIPEMD_160 20131128 + + +mdx_hash + diff --git a/src/lib/hash/rmd160/rmd160.cpp b/src/lib/hash/rmd160/rmd160.cpp new file mode 100644 index 000000000..ff1c1c4ec --- /dev/null +++ b/src/lib/hash/rmd160/rmd160.cpp @@ -0,0 +1,210 @@ +/* +* RIPEMD-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* RIPEMD-160 F1 Function +*/ +inline void F1(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift) + { + A += (B ^ C ^ D) + msg; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F2 Function +*/ +inline void F2(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B & (C ^ D))) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F3 Function +*/ +inline void F3(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B | ~C)) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F4 Function +*/ +inline void F4(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (C ^ (D & (B ^ C))) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F5 Function +*/ +inline void F5(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (B ^ (C | ~D)) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +} + +/* +* RIPEMD-160 Compression Function +*/ +void RIPEMD_160::compress_n(const byte input[], size_t blocks) + { + const u32bit MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1, + MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0xA953FD4E, + MAGIC6 = 0x50A28BE6, MAGIC7 = 0x5C4DD124, + MAGIC8 = 0x6D703EF3, MAGIC9 = 0x7A6D76E9; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + u32bit A1 = digest[0], A2 = A1, B1 = digest[1], B2 = B1, + C1 = digest[2], C2 = C1, D1 = digest[3], D2 = D1, + E1 = digest[4], E2 = E1; + + F1(A1,B1,C1,D1,E1,M[ 0],11 ); F5(A2,B2,C2,D2,E2,M[ 5], 8,MAGIC6); + F1(E1,A1,B1,C1,D1,M[ 1],14 ); F5(E2,A2,B2,C2,D2,M[14], 9,MAGIC6); + F1(D1,E1,A1,B1,C1,M[ 2],15 ); F5(D2,E2,A2,B2,C2,M[ 7], 9,MAGIC6); + F1(C1,D1,E1,A1,B1,M[ 3],12 ); F5(C2,D2,E2,A2,B2,M[ 0],11,MAGIC6); + F1(B1,C1,D1,E1,A1,M[ 4], 5 ); F5(B2,C2,D2,E2,A2,M[ 9],13,MAGIC6); + F1(A1,B1,C1,D1,E1,M[ 5], 8 ); F5(A2,B2,C2,D2,E2,M[ 2],15,MAGIC6); + F1(E1,A1,B1,C1,D1,M[ 6], 7 ); F5(E2,A2,B2,C2,D2,M[11],15,MAGIC6); + F1(D1,E1,A1,B1,C1,M[ 7], 9 ); F5(D2,E2,A2,B2,C2,M[ 4], 5,MAGIC6); + F1(C1,D1,E1,A1,B1,M[ 8],11 ); F5(C2,D2,E2,A2,B2,M[13], 7,MAGIC6); + F1(B1,C1,D1,E1,A1,M[ 9],13 ); F5(B2,C2,D2,E2,A2,M[ 6], 7,MAGIC6); + F1(A1,B1,C1,D1,E1,M[10],14 ); F5(A2,B2,C2,D2,E2,M[15], 8,MAGIC6); + F1(E1,A1,B1,C1,D1,M[11],15 ); F5(E2,A2,B2,C2,D2,M[ 8],11,MAGIC6); + F1(D1,E1,A1,B1,C1,M[12], 6 ); F5(D2,E2,A2,B2,C2,M[ 1],14,MAGIC6); + F1(C1,D1,E1,A1,B1,M[13], 7 ); F5(C2,D2,E2,A2,B2,M[10],14,MAGIC6); + F1(B1,C1,D1,E1,A1,M[14], 9 ); F5(B2,C2,D2,E2,A2,M[ 3],12,MAGIC6); + F1(A1,B1,C1,D1,E1,M[15], 8 ); F5(A2,B2,C2,D2,E2,M[12], 6,MAGIC6); + + F2(E1,A1,B1,C1,D1,M[ 7], 7,MAGIC2); F4(E2,A2,B2,C2,D2,M[ 6], 9,MAGIC7); + F2(D1,E1,A1,B1,C1,M[ 4], 6,MAGIC2); F4(D2,E2,A2,B2,C2,M[11],13,MAGIC7); + F2(C1,D1,E1,A1,B1,M[13], 8,MAGIC2); F4(C2,D2,E2,A2,B2,M[ 3],15,MAGIC7); + F2(B1,C1,D1,E1,A1,M[ 1],13,MAGIC2); F4(B2,C2,D2,E2,A2,M[ 7], 7,MAGIC7); + F2(A1,B1,C1,D1,E1,M[10],11,MAGIC2); F4(A2,B2,C2,D2,E2,M[ 0],12,MAGIC7); + F2(E1,A1,B1,C1,D1,M[ 6], 9,MAGIC2); F4(E2,A2,B2,C2,D2,M[13], 8,MAGIC7); + F2(D1,E1,A1,B1,C1,M[15], 7,MAGIC2); F4(D2,E2,A2,B2,C2,M[ 5], 9,MAGIC7); + F2(C1,D1,E1,A1,B1,M[ 3],15,MAGIC2); F4(C2,D2,E2,A2,B2,M[10],11,MAGIC7); + F2(B1,C1,D1,E1,A1,M[12], 7,MAGIC2); F4(B2,C2,D2,E2,A2,M[14], 7,MAGIC7); + F2(A1,B1,C1,D1,E1,M[ 0],12,MAGIC2); F4(A2,B2,C2,D2,E2,M[15], 7,MAGIC7); + F2(E1,A1,B1,C1,D1,M[ 9],15,MAGIC2); F4(E2,A2,B2,C2,D2,M[ 8],12,MAGIC7); + F2(D1,E1,A1,B1,C1,M[ 5], 9,MAGIC2); F4(D2,E2,A2,B2,C2,M[12], 7,MAGIC7); + F2(C1,D1,E1,A1,B1,M[ 2],11,MAGIC2); F4(C2,D2,E2,A2,B2,M[ 4], 6,MAGIC7); + F2(B1,C1,D1,E1,A1,M[14], 7,MAGIC2); F4(B2,C2,D2,E2,A2,M[ 9],15,MAGIC7); + F2(A1,B1,C1,D1,E1,M[11],13,MAGIC2); F4(A2,B2,C2,D2,E2,M[ 1],13,MAGIC7); + F2(E1,A1,B1,C1,D1,M[ 8],12,MAGIC2); F4(E2,A2,B2,C2,D2,M[ 2],11,MAGIC7); + + F3(D1,E1,A1,B1,C1,M[ 3],11,MAGIC3); F3(D2,E2,A2,B2,C2,M[15], 9,MAGIC8); + F3(C1,D1,E1,A1,B1,M[10],13,MAGIC3); F3(C2,D2,E2,A2,B2,M[ 5], 7,MAGIC8); + F3(B1,C1,D1,E1,A1,M[14], 6,MAGIC3); F3(B2,C2,D2,E2,A2,M[ 1],15,MAGIC8); + F3(A1,B1,C1,D1,E1,M[ 4], 7,MAGIC3); F3(A2,B2,C2,D2,E2,M[ 3],11,MAGIC8); + F3(E1,A1,B1,C1,D1,M[ 9],14,MAGIC3); F3(E2,A2,B2,C2,D2,M[ 7], 8,MAGIC8); + F3(D1,E1,A1,B1,C1,M[15], 9,MAGIC3); F3(D2,E2,A2,B2,C2,M[14], 6,MAGIC8); + F3(C1,D1,E1,A1,B1,M[ 8],13,MAGIC3); F3(C2,D2,E2,A2,B2,M[ 6], 6,MAGIC8); + F3(B1,C1,D1,E1,A1,M[ 1],15,MAGIC3); F3(B2,C2,D2,E2,A2,M[ 9],14,MAGIC8); + F3(A1,B1,C1,D1,E1,M[ 2],14,MAGIC3); F3(A2,B2,C2,D2,E2,M[11],12,MAGIC8); + F3(E1,A1,B1,C1,D1,M[ 7], 8,MAGIC3); F3(E2,A2,B2,C2,D2,M[ 8],13,MAGIC8); + F3(D1,E1,A1,B1,C1,M[ 0],13,MAGIC3); F3(D2,E2,A2,B2,C2,M[12], 5,MAGIC8); + F3(C1,D1,E1,A1,B1,M[ 6], 6,MAGIC3); F3(C2,D2,E2,A2,B2,M[ 2],14,MAGIC8); + F3(B1,C1,D1,E1,A1,M[13], 5,MAGIC3); F3(B2,C2,D2,E2,A2,M[10],13,MAGIC8); + F3(A1,B1,C1,D1,E1,M[11],12,MAGIC3); F3(A2,B2,C2,D2,E2,M[ 0],13,MAGIC8); + F3(E1,A1,B1,C1,D1,M[ 5], 7,MAGIC3); F3(E2,A2,B2,C2,D2,M[ 4], 7,MAGIC8); + F3(D1,E1,A1,B1,C1,M[12], 5,MAGIC3); F3(D2,E2,A2,B2,C2,M[13], 5,MAGIC8); + + F4(C1,D1,E1,A1,B1,M[ 1],11,MAGIC4); F2(C2,D2,E2,A2,B2,M[ 8],15,MAGIC9); + F4(B1,C1,D1,E1,A1,M[ 9],12,MAGIC4); F2(B2,C2,D2,E2,A2,M[ 6], 5,MAGIC9); + F4(A1,B1,C1,D1,E1,M[11],14,MAGIC4); F2(A2,B2,C2,D2,E2,M[ 4], 8,MAGIC9); + F4(E1,A1,B1,C1,D1,M[10],15,MAGIC4); F2(E2,A2,B2,C2,D2,M[ 1],11,MAGIC9); + F4(D1,E1,A1,B1,C1,M[ 0],14,MAGIC4); F2(D2,E2,A2,B2,C2,M[ 3],14,MAGIC9); + F4(C1,D1,E1,A1,B1,M[ 8],15,MAGIC4); F2(C2,D2,E2,A2,B2,M[11],14,MAGIC9); + F4(B1,C1,D1,E1,A1,M[12], 9,MAGIC4); F2(B2,C2,D2,E2,A2,M[15], 6,MAGIC9); + F4(A1,B1,C1,D1,E1,M[ 4], 8,MAGIC4); F2(A2,B2,C2,D2,E2,M[ 0],14,MAGIC9); + F4(E1,A1,B1,C1,D1,M[13], 9,MAGIC4); F2(E2,A2,B2,C2,D2,M[ 5], 6,MAGIC9); + F4(D1,E1,A1,B1,C1,M[ 3],14,MAGIC4); F2(D2,E2,A2,B2,C2,M[12], 9,MAGIC9); + F4(C1,D1,E1,A1,B1,M[ 7], 5,MAGIC4); F2(C2,D2,E2,A2,B2,M[ 2],12,MAGIC9); + F4(B1,C1,D1,E1,A1,M[15], 6,MAGIC4); F2(B2,C2,D2,E2,A2,M[13], 9,MAGIC9); + F4(A1,B1,C1,D1,E1,M[14], 8,MAGIC4); F2(A2,B2,C2,D2,E2,M[ 9],12,MAGIC9); + F4(E1,A1,B1,C1,D1,M[ 5], 6,MAGIC4); F2(E2,A2,B2,C2,D2,M[ 7], 5,MAGIC9); + F4(D1,E1,A1,B1,C1,M[ 6], 5,MAGIC4); F2(D2,E2,A2,B2,C2,M[10],15,MAGIC9); + F4(C1,D1,E1,A1,B1,M[ 2],12,MAGIC4); F2(C2,D2,E2,A2,B2,M[14], 8,MAGIC9); + + F5(B1,C1,D1,E1,A1,M[ 4], 9,MAGIC5); F1(B2,C2,D2,E2,A2,M[12], 8 ); + F5(A1,B1,C1,D1,E1,M[ 0],15,MAGIC5); F1(A2,B2,C2,D2,E2,M[15], 5 ); + F5(E1,A1,B1,C1,D1,M[ 5], 5,MAGIC5); F1(E2,A2,B2,C2,D2,M[10],12 ); + F5(D1,E1,A1,B1,C1,M[ 9],11,MAGIC5); F1(D2,E2,A2,B2,C2,M[ 4], 9 ); + F5(C1,D1,E1,A1,B1,M[ 7], 6,MAGIC5); F1(C2,D2,E2,A2,B2,M[ 1],12 ); + F5(B1,C1,D1,E1,A1,M[12], 8,MAGIC5); F1(B2,C2,D2,E2,A2,M[ 5], 5 ); + F5(A1,B1,C1,D1,E1,M[ 2],13,MAGIC5); F1(A2,B2,C2,D2,E2,M[ 8],14 ); + F5(E1,A1,B1,C1,D1,M[10],12,MAGIC5); F1(E2,A2,B2,C2,D2,M[ 7], 6 ); + F5(D1,E1,A1,B1,C1,M[14], 5,MAGIC5); F1(D2,E2,A2,B2,C2,M[ 6], 8 ); + F5(C1,D1,E1,A1,B1,M[ 1],12,MAGIC5); F1(C2,D2,E2,A2,B2,M[ 2],13 ); + F5(B1,C1,D1,E1,A1,M[ 3],13,MAGIC5); F1(B2,C2,D2,E2,A2,M[13], 6 ); + F5(A1,B1,C1,D1,E1,M[ 8],14,MAGIC5); F1(A2,B2,C2,D2,E2,M[14], 5 ); + F5(E1,A1,B1,C1,D1,M[11],11,MAGIC5); F1(E2,A2,B2,C2,D2,M[ 0],15 ); + F5(D1,E1,A1,B1,C1,M[ 6], 8,MAGIC5); F1(D2,E2,A2,B2,C2,M[ 3],13 ); + F5(C1,D1,E1,A1,B1,M[15], 5,MAGIC5); F1(C2,D2,E2,A2,B2,M[ 9],11 ); + F5(B1,C1,D1,E1,A1,M[13], 6,MAGIC5); F1(B2,C2,D2,E2,A2,M[11],11 ); + + C1 = digest[1] + C1 + D2; + digest[1] = digest[2] + D1 + E2; + digest[2] = digest[3] + E1 + A2; + digest[3] = digest[4] + A1 + B2; + digest[4] = digest[0] + B1 + C2; + digest[0] = C1; + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void RIPEMD_160::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void RIPEMD_160::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} diff --git a/src/lib/hash/rmd160/rmd160.h b/src/lib/hash/rmd160/rmd160.h new file mode 100644 index 000000000..0e43fed9a --- /dev/null +++ b/src/lib/hash/rmd160/rmd160.h @@ -0,0 +1,38 @@ +/* +* RIPEMD-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RIPEMD_160_H__ +#define BOTAN_RIPEMD_160_H__ + +#include + +namespace Botan { + +/** +* RIPEMD-160 +*/ +class BOTAN_DLL RIPEMD_160 : public MDx_HashFunction + { + public: + std::string name() const { return "RIPEMD-160"; } + size_t output_length() const { return 20; } + HashFunction* clone() const { return new RIPEMD_160; } + + void clear(); + + RIPEMD_160() : MDx_HashFunction(64, false, true), M(16), digest(5) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector M, digest; + }; + +} + +#endif diff --git a/src/lib/hash/sha1/info.txt b/src/lib/hash/sha1/info.txt new file mode 100644 index 000000000..fffb51275 --- /dev/null +++ b/src/lib/hash/sha1/info.txt @@ -0,0 +1,5 @@ +define SHA1 20131128 + + +mdx_hash + diff --git a/src/lib/hash/sha1/sha160.cpp b/src/lib/hash/sha1/sha160.cpp new file mode 100644 index 000000000..f5daaadb2 --- /dev/null +++ b/src/lib/hash/sha1/sha160.cpp @@ -0,0 +1,161 @@ +/* +* SHA-160 +* (C) 1999-2008,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace SHA1_F { + +namespace { + +/* +* SHA-160 F1 Function +*/ +inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +} + +} + +/* +* SHA-160 Compression Function +*/ +void SHA_160::compress_n(const byte input[], size_t blocks) + { + using namespace SHA1_F; + + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4]; + + for(size_t i = 0; i != blocks; ++i) + { + load_be(&W[0], input, 16); + + for(size_t j = 16; j != 80; j += 8) + { + W[j ] = rotate_left((W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16]), 1); + W[j+1] = rotate_left((W[j-2] ^ W[j-7] ^ W[j-13] ^ W[j-15]), 1); + W[j+2] = rotate_left((W[j-1] ^ W[j-6] ^ W[j-12] ^ W[j-14]), 1); + W[j+3] = rotate_left((W[j ] ^ W[j-5] ^ W[j-11] ^ W[j-13]), 1); + W[j+4] = rotate_left((W[j+1] ^ W[j-4] ^ W[j-10] ^ W[j-12]), 1); + W[j+5] = rotate_left((W[j+2] ^ W[j-3] ^ W[j- 9] ^ W[j-11]), 1); + W[j+6] = rotate_left((W[j+3] ^ W[j-2] ^ W[j- 8] ^ W[j-10]), 1); + W[j+7] = rotate_left((W[j+4] ^ W[j-1] ^ W[j- 7] ^ W[j- 9]), 1); + } + + F1(A, B, C, D, E, W[ 0]); F1(E, A, B, C, D, W[ 1]); + F1(D, E, A, B, C, W[ 2]); F1(C, D, E, A, B, W[ 3]); + F1(B, C, D, E, A, W[ 4]); F1(A, B, C, D, E, W[ 5]); + F1(E, A, B, C, D, W[ 6]); F1(D, E, A, B, C, W[ 7]); + F1(C, D, E, A, B, W[ 8]); F1(B, C, D, E, A, W[ 9]); + F1(A, B, C, D, E, W[10]); F1(E, A, B, C, D, W[11]); + F1(D, E, A, B, C, W[12]); F1(C, D, E, A, B, W[13]); + F1(B, C, D, E, A, W[14]); F1(A, B, C, D, E, W[15]); + F1(E, A, B, C, D, W[16]); F1(D, E, A, B, C, W[17]); + F1(C, D, E, A, B, W[18]); F1(B, C, D, E, A, W[19]); + + F2(A, B, C, D, E, W[20]); F2(E, A, B, C, D, W[21]); + F2(D, E, A, B, C, W[22]); F2(C, D, E, A, B, W[23]); + F2(B, C, D, E, A, W[24]); F2(A, B, C, D, E, W[25]); + F2(E, A, B, C, D, W[26]); F2(D, E, A, B, C, W[27]); + F2(C, D, E, A, B, W[28]); F2(B, C, D, E, A, W[29]); + F2(A, B, C, D, E, W[30]); F2(E, A, B, C, D, W[31]); + F2(D, E, A, B, C, W[32]); F2(C, D, E, A, B, W[33]); + F2(B, C, D, E, A, W[34]); F2(A, B, C, D, E, W[35]); + F2(E, A, B, C, D, W[36]); F2(D, E, A, B, C, W[37]); + F2(C, D, E, A, B, W[38]); F2(B, C, D, E, A, W[39]); + + F3(A, B, C, D, E, W[40]); F3(E, A, B, C, D, W[41]); + F3(D, E, A, B, C, W[42]); F3(C, D, E, A, B, W[43]); + F3(B, C, D, E, A, W[44]); F3(A, B, C, D, E, W[45]); + F3(E, A, B, C, D, W[46]); F3(D, E, A, B, C, W[47]); + F3(C, D, E, A, B, W[48]); F3(B, C, D, E, A, W[49]); + F3(A, B, C, D, E, W[50]); F3(E, A, B, C, D, W[51]); + F3(D, E, A, B, C, W[52]); F3(C, D, E, A, B, W[53]); + F3(B, C, D, E, A, W[54]); F3(A, B, C, D, E, W[55]); + F3(E, A, B, C, D, W[56]); F3(D, E, A, B, C, W[57]); + F3(C, D, E, A, B, W[58]); F3(B, C, D, E, A, W[59]); + + F4(A, B, C, D, E, W[60]); F4(E, A, B, C, D, W[61]); + F4(D, E, A, B, C, W[62]); F4(C, D, E, A, B, W[63]); + F4(B, C, D, E, A, W[64]); F4(A, B, C, D, E, W[65]); + F4(E, A, B, C, D, W[66]); F4(D, E, A, B, C, W[67]); + F4(C, D, E, A, B, W[68]); F4(B, C, D, E, A, W[69]); + F4(A, B, C, D, E, W[70]); F4(E, A, B, C, D, W[71]); + F4(D, E, A, B, C, W[72]); F4(C, D, E, A, B, W[73]); + F4(B, C, D, E, A, W[74]); F4(A, B, C, D, E, W[75]); + F4(E, A, B, C, D, W[76]); F4(D, E, A, B, C, W[77]); + F4(C, D, E, A, B, W[78]); F4(B, C, D, E, A, W[79]); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void SHA_160::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_be(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_160::clear() + { + MDx_HashFunction::clear(); + zeroise(W); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} diff --git a/src/lib/hash/sha1/sha160.h b/src/lib/hash/sha1/sha160.h new file mode 100644 index 000000000..e2a81808d --- /dev/null +++ b/src/lib/hash/sha1/sha160.h @@ -0,0 +1,60 @@ +/* +* SHA-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_160_H__ +#define BOTAN_SHA_160_H__ + +#include + +namespace Botan { + +/** +* NIST's SHA-160 +*/ +class BOTAN_DLL SHA_160 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-160"; } + size_t output_length() const { return 20; } + HashFunction* clone() const { return new SHA_160; } + + void clear(); + + SHA_160() : MDx_HashFunction(64, true, true), digest(5), W(80) + { + clear(); + } + protected: + /** + * Set a custom size for the W array. Normally 80, but some + * subclasses need slightly more for best performance/internal + * constraints + * @param W_size how big to make W + */ + SHA_160(size_t W_size) : + MDx_HashFunction(64, true, true), digest(5), W(W_size) + { + clear(); + } + + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + /** + * The digest value, exposed for use by subclasses (asm, SSE2) + */ + secure_vector digest; + + /** + * The message buffer, exposed for use by subclasses (asm, SSE2) + */ + secure_vector W; + }; + +} + +#endif diff --git a/src/lib/hash/sha1_sse2/info.txt b/src/lib/hash/sha1_sse2/info.txt new file mode 100644 index 000000000..8d4926e63 --- /dev/null +++ b/src/lib/hash/sha1_sse2/info.txt @@ -0,0 +1,8 @@ +define SHA1_SSE2 20131128 + +need_isa sse2 + + +sha1 +simd_engine + diff --git a/src/lib/hash/sha1_sse2/sha1_sse2.cpp b/src/lib/hash/sha1_sse2/sha1_sse2.cpp new file mode 100644 index 000000000..f96afd9ce --- /dev/null +++ b/src/lib/hash/sha1_sse2/sha1_sse2.cpp @@ -0,0 +1,335 @@ +/* +* SHA-1 using SSE2 +* (C) 2009-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +* +* Based on public domain code by Dean Gaudet +* (http://arctic.org/~dean/crypto/sha1.html) +*/ + +#include +#include +#include + +namespace Botan { + +namespace SHA1_SSE2_F { + +namespace { + +/* +* First 16 bytes just need byte swapping. Preparing just means +* adding in the round constants. +*/ + +#define prep00_15(P, W) \ + do { \ + W = _mm_shufflehi_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ + W = _mm_shufflelo_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ + W = _mm_or_si128(_mm_slli_epi16(W, 8), \ + _mm_srli_epi16(W, 8)); \ + P.u128 = _mm_add_epi32(W, K00_19); \ + } while(0) + +/* +For each multiple of 4, t, we want to calculate this: + +W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); +W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); +W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); +W[t+3] = rol(W[t] ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); + +we'll actually calculate this: + +W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); +W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); +W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); +W[t+3] = rol( 0 ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); +W[t+3] ^= rol(W[t+0], 1); + +the parameters are: + +W0 = &W[t-16]; +W1 = &W[t-12]; +W2 = &W[t- 8]; +W3 = &W[t- 4]; + +and on output: +prepared = W0 + K +W0 = W[t]..W[t+3] +*/ + +/* note that there is a step here where i want to do a rol by 1, which +* normally would look like this: +* +* r1 = psrld r0,$31 +* r0 = pslld r0,$1 +* r0 = por r0,r1 +* +* but instead i do this: +* +* r1 = pcmpltd r0,zero +* r0 = paddd r0,r0 +* r0 = psub r0,r1 +* +* because pcmpltd and paddd are availabe in both MMX units on +* efficeon, pentium-m, and opteron but shifts are available in +* only one unit. +*/ +#define prep(prep, XW0, XW1, XW2, XW3, K) \ + do { \ + __m128i r0, r1, r2, r3; \ + \ + /* load W[t-4] 16-byte aligned, and shift */ \ + r3 = _mm_srli_si128((XW3), 4); \ + r0 = (XW0); \ + /* get high 64-bits of XW0 into low 64-bits */ \ + r1 = _mm_shuffle_epi32((XW0), _MM_SHUFFLE(1,0,3,2)); \ + /* load high 64-bits of r1 */ \ + r1 = _mm_unpacklo_epi64(r1, (XW1)); \ + r2 = (XW2); \ + \ + r0 = _mm_xor_si128(r1, r0); \ + r2 = _mm_xor_si128(r3, r2); \ + r0 = _mm_xor_si128(r2, r0); \ + /* unrotated W[t]..W[t+2] in r0 ... still need W[t+3] */ \ + \ + r2 = _mm_slli_si128(r0, 12); \ + r1 = _mm_cmplt_epi32(r0, _mm_setzero_si128()); \ + r0 = _mm_add_epi32(r0, r0); /* shift left by 1 */ \ + r0 = _mm_sub_epi32(r0, r1); /* r0 has W[t]..W[t+2] */ \ + \ + r3 = _mm_srli_epi32(r2, 30); \ + r2 = _mm_slli_epi32(r2, 2); \ + \ + r0 = _mm_xor_si128(r0, r3); \ + r0 = _mm_xor_si128(r0, r2); /* r0 now has W[t+3] */ \ + \ + (XW0) = r0; \ + (prep).u128 = _mm_add_epi32(r0, K); \ + } while(0) + +/* +* SHA-160 F1 Function +*/ +inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (D ^ (B & (C ^ D))) + msg + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (B ^ C ^ D) + msg + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += ((B & C) | ((B | C) & D)) + msg + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (B ^ C ^ D) + msg + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +} + +} + +/* +* SHA-160 Compression Function using SSE for message expansion +*/ +void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) + { + using namespace SHA1_SSE2_F; + + const __m128i K00_19 = _mm_set1_epi32(0x5A827999); + const __m128i K20_39 = _mm_set1_epi32(0x6ED9EBA1); + const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC); + const __m128i K60_79 = _mm_set1_epi32(0xCA62C1D6); + + u32bit A = digest[0], + B = digest[1], + C = digest[2], + D = digest[3], + E = digest[4]; + + const __m128i* input = reinterpret_cast(input_bytes); + + for(size_t i = 0; i != blocks; ++i) + { + union v4si { + u32bit u32[4]; + __m128i u128; + }; + + v4si P0, P1, P2, P3; + + __m128i W0 = _mm_loadu_si128(&input[0]); + prep00_15(P0, W0); + + __m128i W1 = _mm_loadu_si128(&input[1]); + prep00_15(P1, W1); + + __m128i W2 = _mm_loadu_si128(&input[2]); + prep00_15(P2, W2); + + __m128i W3 = _mm_loadu_si128(&input[3]); + prep00_15(P3, W3); + + /* + Using SSE4; slower on Core2 and Nehalem + #define GET_P_32(P, i) _mm_extract_epi32(P.u128, i) + + Much slower on all tested platforms + #define GET_P_32(P,i) _mm_cvtsi128_si32(_mm_srli_si128(P.u128, i*4)) + */ + +#define GET_P_32(P, i) P.u32[i] + + F1(A, B, C, D, E, GET_P_32(P0, 0)); + F1(E, A, B, C, D, GET_P_32(P0, 1)); + F1(D, E, A, B, C, GET_P_32(P0, 2)); + F1(C, D, E, A, B, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K00_19); + + F1(B, C, D, E, A, GET_P_32(P1, 0)); + F1(A, B, C, D, E, GET_P_32(P1, 1)); + F1(E, A, B, C, D, GET_P_32(P1, 2)); + F1(D, E, A, B, C, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K20_39); + + F1(C, D, E, A, B, GET_P_32(P2, 0)); + F1(B, C, D, E, A, GET_P_32(P2, 1)); + F1(A, B, C, D, E, GET_P_32(P2, 2)); + F1(E, A, B, C, D, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K20_39); + + F1(D, E, A, B, C, GET_P_32(P3, 0)); + F1(C, D, E, A, B, GET_P_32(P3, 1)); + F1(B, C, D, E, A, GET_P_32(P3, 2)); + F1(A, B, C, D, E, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K20_39); + + F1(E, A, B, C, D, GET_P_32(P0, 0)); + F1(D, E, A, B, C, GET_P_32(P0, 1)); + F1(C, D, E, A, B, GET_P_32(P0, 2)); + F1(B, C, D, E, A, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K20_39); + + F2(A, B, C, D, E, GET_P_32(P1, 0)); + F2(E, A, B, C, D, GET_P_32(P1, 1)); + F2(D, E, A, B, C, GET_P_32(P1, 2)); + F2(C, D, E, A, B, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K20_39); + + F2(B, C, D, E, A, GET_P_32(P2, 0)); + F2(A, B, C, D, E, GET_P_32(P2, 1)); + F2(E, A, B, C, D, GET_P_32(P2, 2)); + F2(D, E, A, B, C, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K40_59); + + F2(C, D, E, A, B, GET_P_32(P3, 0)); + F2(B, C, D, E, A, GET_P_32(P3, 1)); + F2(A, B, C, D, E, GET_P_32(P3, 2)); + F2(E, A, B, C, D, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K40_59); + + F2(D, E, A, B, C, GET_P_32(P0, 0)); + F2(C, D, E, A, B, GET_P_32(P0, 1)); + F2(B, C, D, E, A, GET_P_32(P0, 2)); + F2(A, B, C, D, E, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K40_59); + + F2(E, A, B, C, D, GET_P_32(P1, 0)); + F2(D, E, A, B, C, GET_P_32(P1, 1)); + F2(C, D, E, A, B, GET_P_32(P1, 2)); + F2(B, C, D, E, A, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K40_59); + + F3(A, B, C, D, E, GET_P_32(P2, 0)); + F3(E, A, B, C, D, GET_P_32(P2, 1)); + F3(D, E, A, B, C, GET_P_32(P2, 2)); + F3(C, D, E, A, B, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K40_59); + + F3(B, C, D, E, A, GET_P_32(P3, 0)); + F3(A, B, C, D, E, GET_P_32(P3, 1)); + F3(E, A, B, C, D, GET_P_32(P3, 2)); + F3(D, E, A, B, C, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K60_79); + + F3(C, D, E, A, B, GET_P_32(P0, 0)); + F3(B, C, D, E, A, GET_P_32(P0, 1)); + F3(A, B, C, D, E, GET_P_32(P0, 2)); + F3(E, A, B, C, D, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K60_79); + + F3(D, E, A, B, C, GET_P_32(P1, 0)); + F3(C, D, E, A, B, GET_P_32(P1, 1)); + F3(B, C, D, E, A, GET_P_32(P1, 2)); + F3(A, B, C, D, E, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K60_79); + + F3(E, A, B, C, D, GET_P_32(P2, 0)); + F3(D, E, A, B, C, GET_P_32(P2, 1)); + F3(C, D, E, A, B, GET_P_32(P2, 2)); + F3(B, C, D, E, A, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K60_79); + + F4(A, B, C, D, E, GET_P_32(P3, 0)); + F4(E, A, B, C, D, GET_P_32(P3, 1)); + F4(D, E, A, B, C, GET_P_32(P3, 2)); + F4(C, D, E, A, B, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K60_79); + + F4(B, C, D, E, A, GET_P_32(P0, 0)); + F4(A, B, C, D, E, GET_P_32(P0, 1)); + F4(E, A, B, C, D, GET_P_32(P0, 2)); + F4(D, E, A, B, C, GET_P_32(P0, 3)); + + F4(C, D, E, A, B, GET_P_32(P1, 0)); + F4(B, C, D, E, A, GET_P_32(P1, 1)); + F4(A, B, C, D, E, GET_P_32(P1, 2)); + F4(E, A, B, C, D, GET_P_32(P1, 3)); + + F4(D, E, A, B, C, GET_P_32(P2, 0)); + F4(C, D, E, A, B, GET_P_32(P2, 1)); + F4(B, C, D, E, A, GET_P_32(P2, 2)); + F4(A, B, C, D, E, GET_P_32(P2, 3)); + + F4(E, A, B, C, D, GET_P_32(P3, 0)); + F4(D, E, A, B, C, GET_P_32(P3, 1)); + F4(C, D, E, A, B, GET_P_32(P3, 2)); + F4(B, C, D, E, A, GET_P_32(P3, 3)); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input += (hash_block_size() / 16); + } + +#undef GET_P_32 + } + +#undef prep00_15 +#undef prep + +} diff --git a/src/lib/hash/sha1_sse2/sha1_sse2.h b/src/lib/hash/sha1_sse2/sha1_sse2.h new file mode 100644 index 000000000..9b7b327f0 --- /dev/null +++ b/src/lib/hash/sha1_sse2/sha1_sse2.h @@ -0,0 +1,29 @@ +/* +* SHA-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_160_SSE2_H__ +#define BOTAN_SHA_160_SSE2_H__ + +#include + +namespace Botan { + +/** +* SHA-160 using SSE2 for the message expansion +*/ +class BOTAN_DLL SHA_160_SSE2 : public SHA_160 + { + public: + HashFunction* clone() const { return new SHA_160_SSE2; } + SHA_160_SSE2() : SHA_160(0) {} // no W needed + private: + void compress_n(const byte[], size_t blocks); + }; + +} + +#endif diff --git a/src/lib/hash/sha1_x86_32/info.txt b/src/lib/hash/sha1_x86_32/info.txt new file mode 100644 index 000000000..51e3f6587 --- /dev/null +++ b/src/lib/hash/sha1_x86_32/info.txt @@ -0,0 +1,12 @@ +define SHA1_X86_32 20131128 + +load_on asm_ok + + +x86_32 + + + +asm_x86_32 +sha1 + diff --git a/src/lib/hash/sha1_x86_32/sha1_x86_32.cpp b/src/lib/hash/sha1_x86_32/sha1_x86_32.cpp new file mode 100644 index 000000000..6a4dc2a1d --- /dev/null +++ b/src/lib/hash/sha1_x86_32/sha1_x86_32.cpp @@ -0,0 +1,31 @@ +/* +* SHA-160 in x86-32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +extern "C" +void botan_sha160_x86_32_compress(u32bit[5], const byte[64], u32bit[81]); + +} + +/* +* SHA-160 Compression Function +*/ +void SHA_160_X86_32::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + botan_sha160_x86_32_compress(&digest[0], input, &W[0]); + input += hash_block_size(); + } + } + +} diff --git a/src/lib/hash/sha1_x86_32/sha1_x86_32.h b/src/lib/hash/sha1_x86_32/sha1_x86_32.h new file mode 100644 index 000000000..b344d4ae2 --- /dev/null +++ b/src/lib/hash/sha1_x86_32/sha1_x86_32.h @@ -0,0 +1,31 @@ +/* +* SHA-160 in x86-32 asm +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_160_X86_32_H__ +#define BOTAN_SHA_160_X86_32_H__ + +#include + +namespace Botan { + +/** +* SHA-160 in x86 assembly +*/ +class BOTAN_DLL SHA_160_X86_32 : public SHA_160 + { + public: + HashFunction* clone() const { return new SHA_160_X86_32; } + + // Note 81 instead of normal 80: x86-32 asm needs an extra temp + SHA_160_X86_32() : SHA_160(81) {} + private: + void compress_n(const byte[], size_t blocks); + }; + +} + +#endif diff --git a/src/lib/hash/sha1_x86_32/sha1_x86_32_imp.S b/src/lib/hash/sha1_x86_32/sha1_x86_32_imp.S new file mode 100644 index 000000000..775ef6854 --- /dev/null +++ b/src/lib/hash/sha1_x86_32/sha1_x86_32_imp.S @@ -0,0 +1,244 @@ +/* +* SHA-1 in x86-32 asm +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +START_LISTING(sha1_x86_32_imp.S) + +START_FUNCTION(botan_sha160_x86_32_compress) + SPILL_REGS() + +#define PUSHED 4 + + ASSIGN(EDI, ARG(2)) + ASSIGN(EBP, ARG(3)) + + ZEROIZE(ESI) + +START_LOOP(.LOAD_INPUT) + ADD_IMM(ESI, 4) + + ASSIGN(EAX, ARRAY4(EDI, 0)) + ASSIGN(EBX, ARRAY4(EDI, 1)) + ASSIGN(ECX, ARRAY4(EDI, 2)) + ASSIGN(EDX, ARRAY4(EDI, 3)) + + ADD_IMM(EDI, 16) + + BSWAP(EAX) + BSWAP(EBX) + BSWAP(ECX) + BSWAP(EDX) + + ASSIGN(ARRAY4_INDIRECT(EBP,ESI,-4), EAX) + ASSIGN(ARRAY4_INDIRECT(EBP,ESI,-3), EBX) + ASSIGN(ARRAY4_INDIRECT(EBP,ESI,-2), ECX) + ASSIGN(ARRAY4_INDIRECT(EBP,ESI,-1), EDX) +LOOP_UNTIL_EQ(ESI, 16, .LOAD_INPUT) + + ADD2_IMM(EDI, EBP, 64) + +START_LOOP(.L_SHA_EXPANSION) + ADD_IMM(ESI, 4) + + ZEROIZE(EAX) + ASSIGN(EBX, ARRAY4(EDI, -1)) + ASSIGN(ECX, ARRAY4(EDI, -2)) + ASSIGN(EDX, ARRAY4(EDI, -3)) + + XOR(EAX, ARRAY4(EDI, -5)) + XOR(EBX, ARRAY4(EDI, -6)) + XOR(ECX, ARRAY4(EDI, -7)) + XOR(EDX, ARRAY4(EDI, -8)) + + XOR(EAX, ARRAY4(EDI, -11)) + XOR(EBX, ARRAY4(EDI, -12)) + XOR(ECX, ARRAY4(EDI, -13)) + XOR(EDX, ARRAY4(EDI, -14)) + + XOR(EAX, ARRAY4(EDI, -13)) + XOR(EBX, ARRAY4(EDI, -14)) + XOR(ECX, ARRAY4(EDI, -15)) + XOR(EDX, ARRAY4(EDI, -16)) + + ROTL_IMM(EDX, 1) + ROTL_IMM(ECX, 1) + ROTL_IMM(EBX, 1) + XOR(EAX, EDX) + ROTL_IMM(EAX, 1) + + ASSIGN(ARRAY4(EDI, 0), EDX) + ASSIGN(ARRAY4(EDI, 1), ECX) + ASSIGN(ARRAY4(EDI, 2), EBX) + ASSIGN(ARRAY4(EDI, 3), EAX) + + ADD_IMM(EDI, 16) +LOOP_UNTIL_EQ(ESI, 80, .L_SHA_EXPANSION) + +#define MAGIC1 0x5A827999 +#define MAGIC2 0x6ED9EBA1 +#define MAGIC3 0x8F1BBCDC +#define MAGIC4 0xCA62C1D6 + +#define MSG ESP +#define T2 EBP + +#define F1(A, B, C, D, E, F, N) \ + ASSIGN(T2, ARRAY4(MSG, N)) ; \ + ASSIGN(A, F) ; \ + ROTL_IMM(F, 5) ; \ + ADD(F, E) ; \ + ASSIGN(E, C) ; \ + XOR(E, D) ; \ + ADD3_IMM(F, T2, MAGIC1) ; \ + AND(E, B) ; \ + XOR(E, D) ; \ + ROTR_IMM(B, 2) ; \ + ADD(E, F) ; + +#define F2_4(A, B, C, D, E, F, N, MAGIC) \ + ASSIGN(T2, ARRAY4(MSG, N)) ; \ + ASSIGN(A, F) ; \ + ROTL_IMM(F, 5) ; \ + ADD(F, E) ; \ + ASSIGN(E, B) ; \ + XOR(E, C) ; \ + ADD3_IMM(F, T2, MAGIC) ; \ + XOR(E, D) ; \ + ROTR_IMM(B, 2) ; \ + ADD(E, F) ; + +#define F3(A, B, C, D, E, F, N) \ + ASSIGN(T2, ARRAY4(MSG, N)) ; \ + ASSIGN(A, F) ; \ + ROTL_IMM(F, 5) ; \ + ADD(F, E) ; \ + ASSIGN(E, B) ; \ + OR(E, C) ; \ + AND(E, D) ; \ + ADD3_IMM(F, T2, MAGIC3) ; \ + ASSIGN(T2, B) ; \ + AND(T2, C) ; \ + OR(E, T2) ; \ + ROTR_IMM(B, 2) ; \ + ADD(E, F) ; + +#define F2(A, B, C, D, E, F, MSG) \ + F2_4(A, B, C, D, E, F, MSG, MAGIC2) + +#define F4(A, B, C, D, E, F, MSG) \ + F2_4(A, B, C, D, E, F, MSG, MAGIC4) + + ASSIGN(EAX, ARG(1)) + ASSIGN(EDI, ARRAY4(EAX, 0)) + ASSIGN(EBX, ARRAY4(EAX, 1)) + ASSIGN(ECX, ARRAY4(EAX, 2)) + ASSIGN(EDX, ARRAY4(EAX, 3)) + ASSIGN(ESI, ARRAY4(EAX, 4)) + + ASSIGN(ARRAY4(EBP, 80), ESP) + ASSIGN(ESP, EBP) + + /* First Round */ + F1(EAX, EBX, ECX, EDX, ESI, EDI, 0) + F1(EDI, EAX, EBX, ECX, EDX, ESI, 1) + F1(ESI, EDI, EAX, EBX, ECX, EDX, 2) + F1(EDX, ESI, EDI, EAX, EBX, ECX, 3) + F1(ECX, EDX, ESI, EDI, EAX, EBX, 4) + F1(EBX, ECX, EDX, ESI, EDI, EAX, 5) + F1(EAX, EBX, ECX, EDX, ESI, EDI, 6) + F1(EDI, EAX, EBX, ECX, EDX, ESI, 7) + F1(ESI, EDI, EAX, EBX, ECX, EDX, 8) + F1(EDX, ESI, EDI, EAX, EBX, ECX, 9) + F1(ECX, EDX, ESI, EDI, EAX, EBX, 10) + F1(EBX, ECX, EDX, ESI, EDI, EAX, 11) + F1(EAX, EBX, ECX, EDX, ESI, EDI, 12) + F1(EDI, EAX, EBX, ECX, EDX, ESI, 13) + F1(ESI, EDI, EAX, EBX, ECX, EDX, 14) + F1(EDX, ESI, EDI, EAX, EBX, ECX, 15) + F1(ECX, EDX, ESI, EDI, EAX, EBX, 16) + F1(EBX, ECX, EDX, ESI, EDI, EAX, 17) + F1(EAX, EBX, ECX, EDX, ESI, EDI, 18) + F1(EDI, EAX, EBX, ECX, EDX, ESI, 19) + + /* Second Round */ + F2(ESI, EDI, EAX, EBX, ECX, EDX, 20) + F2(EDX, ESI, EDI, EAX, EBX, ECX, 21) + F2(ECX, EDX, ESI, EDI, EAX, EBX, 22) + F2(EBX, ECX, EDX, ESI, EDI, EAX, 23) + F2(EAX, EBX, ECX, EDX, ESI, EDI, 24) + F2(EDI, EAX, EBX, ECX, EDX, ESI, 25) + F2(ESI, EDI, EAX, EBX, ECX, EDX, 26) + F2(EDX, ESI, EDI, EAX, EBX, ECX, 27) + F2(ECX, EDX, ESI, EDI, EAX, EBX, 28) + F2(EBX, ECX, EDX, ESI, EDI, EAX, 29) + F2(EAX, EBX, ECX, EDX, ESI, EDI, 30) + F2(EDI, EAX, EBX, ECX, EDX, ESI, 31) + F2(ESI, EDI, EAX, EBX, ECX, EDX, 32) + F2(EDX, ESI, EDI, EAX, EBX, ECX, 33) + F2(ECX, EDX, ESI, EDI, EAX, EBX, 34) + F2(EBX, ECX, EDX, ESI, EDI, EAX, 35) + F2(EAX, EBX, ECX, EDX, ESI, EDI, 36) + F2(EDI, EAX, EBX, ECX, EDX, ESI, 37) + F2(ESI, EDI, EAX, EBX, ECX, EDX, 38) + F2(EDX, ESI, EDI, EAX, EBX, ECX, 39) + + /* Third Round */ + F3(ECX, EDX, ESI, EDI, EAX, EBX, 40) + F3(EBX, ECX, EDX, ESI, EDI, EAX, 41) + F3(EAX, EBX, ECX, EDX, ESI, EDI, 42) + F3(EDI, EAX, EBX, ECX, EDX, ESI, 43) + F3(ESI, EDI, EAX, EBX, ECX, EDX, 44) + F3(EDX, ESI, EDI, EAX, EBX, ECX, 45) + F3(ECX, EDX, ESI, EDI, EAX, EBX, 46) + F3(EBX, ECX, EDX, ESI, EDI, EAX, 47) + F3(EAX, EBX, ECX, EDX, ESI, EDI, 48) + F3(EDI, EAX, EBX, ECX, EDX, ESI, 49) + F3(ESI, EDI, EAX, EBX, ECX, EDX, 50) + F3(EDX, ESI, EDI, EAX, EBX, ECX, 51) + F3(ECX, EDX, ESI, EDI, EAX, EBX, 52) + F3(EBX, ECX, EDX, ESI, EDI, EAX, 53) + F3(EAX, EBX, ECX, EDX, ESI, EDI, 54) + F3(EDI, EAX, EBX, ECX, EDX, ESI, 55) + F3(ESI, EDI, EAX, EBX, ECX, EDX, 56) + F3(EDX, ESI, EDI, EAX, EBX, ECX, 57) + F3(ECX, EDX, ESI, EDI, EAX, EBX, 58) + F3(EBX, ECX, EDX, ESI, EDI, EAX, 59) + + /* Fourth Round */ + F4(EAX, EBX, ECX, EDX, ESI, EDI, 60) + F4(EDI, EAX, EBX, ECX, EDX, ESI, 61) + F4(ESI, EDI, EAX, EBX, ECX, EDX, 62) + F4(EDX, ESI, EDI, EAX, EBX, ECX, 63) + F4(ECX, EDX, ESI, EDI, EAX, EBX, 64) + F4(EBX, ECX, EDX, ESI, EDI, EAX, 65) + F4(EAX, EBX, ECX, EDX, ESI, EDI, 66) + F4(EDI, EAX, EBX, ECX, EDX, ESI, 67) + F4(ESI, EDI, EAX, EBX, ECX, EDX, 68) + F4(EDX, ESI, EDI, EAX, EBX, ECX, 69) + F4(ECX, EDX, ESI, EDI, EAX, EBX, 70) + F4(EBX, ECX, EDX, ESI, EDI, EAX, 71) + F4(EAX, EBX, ECX, EDX, ESI, EDI, 72) + F4(EDI, EAX, EBX, ECX, EDX, ESI, 73) + F4(ESI, EDI, EAX, EBX, ECX, EDX, 74) + F4(EDX, ESI, EDI, EAX, EBX, ECX, 75) + F4(ECX, EDX, ESI, EDI, EAX, EBX, 76) + F4(EBX, ECX, EDX, ESI, EDI, EAX, 77) + F4(EAX, EBX, ECX, EDX, ESI, EDI, 78) + F4(EDI, EAX, EBX, ECX, EDX, ESI, 79) + + ASSIGN(ESP, ARRAY4(ESP, 80)) + + ASSIGN(EBP, ARG(1)) + ADD(ARRAY4(EBP, 0), EDX) + ADD(ARRAY4(EBP, 1), EDI) + ADD(ARRAY4(EBP, 2), EAX) + ADD(ARRAY4(EBP, 3), EBX) + ADD(ARRAY4(EBP, 4), ECX) + + RESTORE_REGS() +END_FUNCTION(botan_sha160_x86_32_compress) diff --git a/src/lib/hash/sha1_x86_64/info.txt b/src/lib/hash/sha1_x86_64/info.txt new file mode 100644 index 000000000..54d5eefff --- /dev/null +++ b/src/lib/hash/sha1_x86_64/info.txt @@ -0,0 +1,13 @@ +define SHA1_X86_64 20131128 + +load_on asm_ok + + +x86_64 + + + +asm_engine +asm_x86_64 +sha1 + diff --git a/src/lib/hash/sha1_x86_64/sha1_x86_64.cpp b/src/lib/hash/sha1_x86_64/sha1_x86_64.cpp new file mode 100644 index 000000000..a3e92e313 --- /dev/null +++ b/src/lib/hash/sha1_x86_64/sha1_x86_64.cpp @@ -0,0 +1,31 @@ +/* +* SHA-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +extern "C" +void botan_sha160_x86_64_compress(u32bit[5], const byte[64], u32bit[80]); + +} + +/* +* SHA-160 Compression Function +*/ +void SHA_160_X86_64::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + botan_sha160_x86_64_compress(&digest[0], input, &W[0]); + input += hash_block_size(); + } + } + +} diff --git a/src/lib/hash/sha1_x86_64/sha1_x86_64.h b/src/lib/hash/sha1_x86_64/sha1_x86_64.h new file mode 100644 index 000000000..068a94595 --- /dev/null +++ b/src/lib/hash/sha1_x86_64/sha1_x86_64.h @@ -0,0 +1,28 @@ +/* +* SHA-160 (x86-64) +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_160_X86_64_H__ +#define BOTAN_SHA_160_X86_64_H__ + +#include + +namespace Botan { + +/** +* SHA-160 in x86-64 assembly +*/ +class BOTAN_DLL SHA_160_X86_64 : public SHA_160 + { + public: + HashFunction* clone() const { return new SHA_160_X86_64; } + private: + void compress_n(const byte[], size_t blocks); + }; + +} + +#endif diff --git a/src/lib/hash/sha1_x86_64/sha1_x86_64_imp.S b/src/lib/hash/sha1_x86_64/sha1_x86_64_imp.S new file mode 100644 index 000000000..ee35f0d85 --- /dev/null +++ b/src/lib/hash/sha1_x86_64/sha1_x86_64_imp.S @@ -0,0 +1,266 @@ +/* +* SHA-1 in x86-64 assembler +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +START_LISTING(sha1_x86_64_imp.S) + +START_FUNCTION(botan_sha160_x86_64_compress) + +#define DIGEST_ARR %rdi +#define INPUT %rsi +#define W %rdx +#define LOOP_CTR %eax + +#define A %r8d +#define B %r9d +#define C %r10d +#define D %r11d +#define E %ecx + + ZEROIZE(LOOP_CTR) + +ALIGN; +.LOOP_LOAD_INPUT: + addl $8, %eax + + movq ARRAY8(INPUT, 0), %r8 + movq ARRAY8(INPUT, 1), %r9 + movq ARRAY8(INPUT, 2), %r10 + movq ARRAY8(INPUT, 3), %r11 + + bswap %r8 + bswap %r9 + bswap %r10 + bswap %r11 + + rolq $32, %r8 + rolq $32, %r9 + rolq $32, %r10 + rolq $32, %r11 + + movq %r8, ARRAY8(W, 0) + movq %r9, ARRAY8(W, 1) + movq %r10, ARRAY8(W, 2) + movq %r11, ARRAY8(W, 3) + + addq $32, W + addq $32, INPUT + + cmp IMM(16), LOOP_CTR + jne .LOOP_LOAD_INPUT + +/* +#define A %r8d +#define B %r9d +#define C %r10d +#define D %r11d +#define E %ecx +*/ + +ALIGN; +.LOOP_EXPANSION: + addl $4, LOOP_CTR + + ZEROIZE(A) + ASSIGN(B, ARRAY4(W, -1)) + ASSIGN(C, ARRAY4(W, -2)) + ASSIGN(D, ARRAY4(W, -3)) + + XOR(A, ARRAY4(W, -5)) + XOR(B, ARRAY4(W, -6)) + XOR(C, ARRAY4(W, -7)) + XOR(D, ARRAY4(W, -8)) + + XOR(A, ARRAY4(W, -11)) + XOR(B, ARRAY4(W, -12)) + XOR(C, ARRAY4(W, -13)) + XOR(D, ARRAY4(W, -14)) + + XOR(A, ARRAY4(W, -13)) + XOR(B, ARRAY4(W, -14)) + XOR(C, ARRAY4(W, -15)) + XOR(D, ARRAY4(W, -16)) + + ROTL_IMM(D, 1) + ROTL_IMM(C, 1) + ROTL_IMM(B, 1) + XOR(A, D) + ROTL_IMM(A, 1) + + ASSIGN(ARRAY4(W, 0), D) + ASSIGN(ARRAY4(W, 1), C) + ASSIGN(ARRAY4(W, 2), B) + ASSIGN(ARRAY4(W, 3), A) + + addq $16, W + cmp IMM(80), LOOP_CTR + jne .LOOP_EXPANSION + + subq $320, W + +/* +* Using negative values for SHA-1 constants > 2^31 to work around +* a bug in binutils not accepting large lea displacements. +* -0x70E44324 == 0x8F1BBCDC +* -0x359D3E2A == 0xCA62C1D6 +*/ +#define MAGIC1 0x5A827999 +#define MAGIC2 0x6ED9EBA1 +#define MAGIC3 -0x70E44324 +#define MAGIC4 -0x359D3E2A + +#define T %esi +#define T2 %eax + +#define F1(A, B, C, D, E, F, N) \ + ASSIGN(T2, ARRAY4(W, N)) ; \ + ASSIGN(A, F) ; \ + ROTL_IMM(F, 5) ; \ + ADD(F, E) ; \ + ASSIGN(E, C) ; \ + XOR(E, D) ; \ + ADD3_IMM(F, T2, MAGIC1) ; \ + AND(E, B) ; \ + XOR(E, D) ; \ + ROTR_IMM(B, 2) ; \ + ADD(E, F) ; + +#define F2_4(A, B, C, D, E, F, N, MAGIC) \ + ASSIGN(T2, ARRAY4(W, N)) ; \ + ASSIGN(A, F) ; \ + ROTL_IMM(F, 5) ; \ + ADD(F, E) ; \ + ASSIGN(E, B) ; \ + XOR(E, C) ; \ + ADD3_IMM(F, T2, MAGIC) ; \ + XOR(E, D) ; \ + ROTR_IMM(B, 2) ; \ + ADD(E, F) ; + +#define F3(A, B, C, D, E, F, N) \ + ASSIGN(T2, ARRAY4(W, N)) ; \ + ASSIGN(A, F) ; \ + ROTL_IMM(F, 5) ; \ + ADD(F, E) ; \ + ASSIGN(E, B) ; \ + OR(E, C) ; \ + AND(E, D) ; \ + ADD3_IMM(F, T2, MAGIC3) ; \ + ASSIGN(T2, B) ; \ + AND(T2, C) ; \ + OR(E, T2) ; \ + ROTR_IMM(B, 2) ; \ + ADD(E, F) ; + +#define F2(A, B, C, D, E, F, W) \ + F2_4(A, B, C, D, E, F, W, MAGIC2) + +#define F4(A, B, C, D, E, F, W) \ + F2_4(A, B, C, D, E, F, W, MAGIC4) + + ASSIGN(T, ARRAY4(DIGEST_ARR, 0)) + ASSIGN(B, ARRAY4(DIGEST_ARR, 1)) + ASSIGN(C, ARRAY4(DIGEST_ARR, 2)) + ASSIGN(D, ARRAY4(DIGEST_ARR, 3)) + ASSIGN(E, ARRAY4(DIGEST_ARR, 4)) + + /* First Round */ + F1(A, B, C, D, E, T, 0) + F1(T, A, B, C, D, E, 1) + F1(E, T, A, B, C, D, 2) + F1(D, E, T, A, B, C, 3) + F1(C, D, E, T, A, B, 4) + F1(B, C, D, E, T, A, 5) + F1(A, B, C, D, E, T, 6) + F1(T, A, B, C, D, E, 7) + F1(E, T, A, B, C, D, 8) + F1(D, E, T, A, B, C, 9) + F1(C, D, E, T, A, B, 10) + F1(B, C, D, E, T, A, 11) + F1(A, B, C, D, E, T, 12) + F1(T, A, B, C, D, E, 13) + F1(E, T, A, B, C, D, 14) + F1(D, E, T, A, B, C, 15) + F1(C, D, E, T, A, B, 16) + F1(B, C, D, E, T, A, 17) + F1(A, B, C, D, E, T, 18) + F1(T, A, B, C, D, E, 19) + + /* Second Round */ + F2(E, T, A, B, C, D, 20) + F2(D, E, T, A, B, C, 21) + F2(C, D, E, T, A, B, 22) + F2(B, C, D, E, T, A, 23) + F2(A, B, C, D, E, T, 24) + F2(T, A, B, C, D, E, 25) + F2(E, T, A, B, C, D, 26) + F2(D, E, T, A, B, C, 27) + F2(C, D, E, T, A, B, 28) + F2(B, C, D, E, T, A, 29) + F2(A, B, C, D, E, T, 30) + F2(T, A, B, C, D, E, 31) + F2(E, T, A, B, C, D, 32) + F2(D, E, T, A, B, C, 33) + F2(C, D, E, T, A, B, 34) + F2(B, C, D, E, T, A, 35) + F2(A, B, C, D, E, T, 36) + F2(T, A, B, C, D, E, 37) + F2(E, T, A, B, C, D, 38) + F2(D, E, T, A, B, C, 39) + + /* Third Round */ + F3(C, D, E, T, A, B, 40) + F3(B, C, D, E, T, A, 41) + F3(A, B, C, D, E, T, 42) + F3(T, A, B, C, D, E, 43) + F3(E, T, A, B, C, D, 44) + F3(D, E, T, A, B, C, 45) + F3(C, D, E, T, A, B, 46) + F3(B, C, D, E, T, A, 47) + F3(A, B, C, D, E, T, 48) + F3(T, A, B, C, D, E, 49) + F3(E, T, A, B, C, D, 50) + F3(D, E, T, A, B, C, 51) + F3(C, D, E, T, A, B, 52) + F3(B, C, D, E, T, A, 53) + F3(A, B, C, D, E, T, 54) + F3(T, A, B, C, D, E, 55) + F3(E, T, A, B, C, D, 56) + F3(D, E, T, A, B, C, 57) + F3(C, D, E, T, A, B, 58) + F3(B, C, D, E, T, A, 59) + + /* Fourth Round */ + F4(A, B, C, D, E, T, 60) + F4(T, A, B, C, D, E, 61) + F4(E, T, A, B, C, D, 62) + F4(D, E, T, A, B, C, 63) + F4(C, D, E, T, A, B, 64) + F4(B, C, D, E, T, A, 65) + F4(A, B, C, D, E, T, 66) + F4(T, A, B, C, D, E, 67) + F4(E, T, A, B, C, D, 68) + F4(D, E, T, A, B, C, 69) + F4(C, D, E, T, A, B, 70) + F4(B, C, D, E, T, A, 71) + F4(A, B, C, D, E, T, 72) + F4(T, A, B, C, D, E, 73) + F4(E, T, A, B, C, D, 74) + F4(D, E, T, A, B, C, 75) + F4(C, D, E, T, A, B, 76) + F4(B, C, D, E, T, A, 77) + F4(A, B, C, D, E, T, 78) + F4(T, A, B, C, D, E, 79) + + ADD(ARRAY4(DIGEST_ARR, 0), D) + ADD(ARRAY4(DIGEST_ARR, 1), T) + ADD(ARRAY4(DIGEST_ARR, 2), A) + ADD(ARRAY4(DIGEST_ARR, 3), B) + ADD(ARRAY4(DIGEST_ARR, 4), C) + +END_FUNCTION(botan_sha160_x86_64_compress) diff --git a/src/lib/hash/sha2_32/info.txt b/src/lib/hash/sha2_32/info.txt new file mode 100644 index 000000000..b15db2ede --- /dev/null +++ b/src/lib/hash/sha2_32/info.txt @@ -0,0 +1,5 @@ +define SHA2_32 20131128 + + +mdx_hash + diff --git a/src/lib/hash/sha2_32/sha2_32.cpp b/src/lib/hash/sha2_32/sha2_32.cpp new file mode 100644 index 000000000..cffc8bd2a --- /dev/null +++ b/src/lib/hash/sha2_32/sha2_32.cpp @@ -0,0 +1,227 @@ +/* +* SHA-{224,256} +* (C) 1999-2010 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +namespace SHA2_32 { + +/* +* SHA-256 Rho Function +*/ +inline u32bit rho(u32bit X, u32bit rot1, u32bit rot2, u32bit rot3) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ + rotate_right(X, rot3)); + } + +/* +* SHA-256 Sigma Function +*/ +inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift)); + } + +/* +* SHA-256 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + H += magic + rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += rho(A, 2, 13, 22) + ((A & B) | ((A | B) & C)); \ + M1 += sigma(M2, 17, 19, 10) + M3 + sigma(M4, 7, 18, 3); \ + } while(0); + +/* +* SHA-224 / SHA-256 compression function +*/ +void compress(secure_vector& digest, + const byte input[], size_t blocks) + { + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit W00 = load_be(input, 0); + u32bit W01 = load_be(input, 1); + u32bit W02 = load_be(input, 2); + u32bit W03 = load_be(input, 3); + u32bit W04 = load_be(input, 4); + u32bit W05 = load_be(input, 5); + u32bit W06 = load_be(input, 6); + u32bit W07 = load_be(input, 7); + u32bit W08 = load_be(input, 8); + u32bit W09 = load_be(input, 9); + u32bit W10 = load_be(input, 10); + u32bit W11 = load_be(input, 11); + u32bit W12 = load_be(input, 12); + u32bit W13 = load_be(input, 13); + u32bit W14 = load_be(input, 14); + u32bit W15 = load_be(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 64; + } + } + +} + +} + +/* +* SHA-224 compression function +*/ +void SHA_224::compress_n(const byte input[], size_t blocks) + { + SHA2_32::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_224::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_be(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_224::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0xC1059ED8; + digest[1] = 0x367CD507; + digest[2] = 0x3070DD17; + digest[3] = 0xF70E5939; + digest[4] = 0xFFC00B31; + digest[5] = 0x68581511; + digest[6] = 0x64F98FA7; + digest[7] = 0xBEFA4FA4; + } + +/* +* SHA-256 compression function +*/ +void SHA_256::compress_n(const byte input[], size_t blocks) + { + SHA2_32::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_256::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_be(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_256::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0x6A09E667; + digest[1] = 0xBB67AE85; + digest[2] = 0x3C6EF372; + digest[3] = 0xA54FF53A; + digest[4] = 0x510E527F; + digest[5] = 0x9B05688C; + digest[6] = 0x1F83D9AB; + digest[7] = 0x5BE0CD19; + } + +} diff --git a/src/lib/hash/sha2_32/sha2_32.h b/src/lib/hash/sha2_32/sha2_32.h new file mode 100644 index 000000000..ccb8e07f2 --- /dev/null +++ b/src/lib/hash/sha2_32/sha2_32.h @@ -0,0 +1,60 @@ +/* +* SHA-{224,256} +* (C) 1999-2011 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_224_256_H__ +#define BOTAN_SHA_224_256_H__ + +#include + +namespace Botan { + +/** +* SHA-224 +*/ +class BOTAN_DLL SHA_224 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-224"; } + size_t output_length() const { return 28; } + HashFunction* clone() const { return new SHA_224; } + + void clear(); + + SHA_224() : MDx_HashFunction(64, true, true), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector digest; + }; + +/** +* SHA-256 +*/ +class BOTAN_DLL SHA_256 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-256"; } + size_t output_length() const { return 32; } + HashFunction* clone() const { return new SHA_256; } + + void clear(); + + SHA_256() : MDx_HashFunction(64, true, true), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector digest; + }; + +} + +#endif diff --git a/src/lib/hash/sha2_64/info.txt b/src/lib/hash/sha2_64/info.txt new file mode 100644 index 000000000..a457dffec --- /dev/null +++ b/src/lib/hash/sha2_64/info.txt @@ -0,0 +1,5 @@ +define SHA2_64 20131128 + + +mdx_hash + diff --git a/src/lib/hash/sha2_64/sha2_64.cpp b/src/lib/hash/sha2_64/sha2_64.cpp new file mode 100644 index 000000000..8dcb4684e --- /dev/null +++ b/src/lib/hash/sha2_64/sha2_64.cpp @@ -0,0 +1,242 @@ +/* +* SHA-{384,512} +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +namespace SHA2_64 { + +/* +* SHA-{384,512} Rho Function +*/ +inline u64bit rho(u64bit X, u32bit rot1, u32bit rot2, u32bit rot3) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ + rotate_right(X, rot3)); + } + +/* +* SHA-{384,512} Sigma Function +*/ +inline u64bit sigma(u64bit X, u32bit rot1, u32bit rot2, u32bit shift) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift)); + } + +/* +* SHA-512 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + H += magic + rho(E, 14, 18, 41) + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += rho(A, 28, 34, 39) + ((A & B) | ((A | B) & C)); \ + M1 += sigma(M2, 19, 61, 6) + M3 + sigma(M4, 1, 8, 7); \ + } while(0); + +/* +* SHA-{384,512} Compression Function +*/ +void compress(secure_vector& digest, + const byte input[], size_t blocks) + { + u64bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + u64bit W00 = load_be(input, 0); + u64bit W01 = load_be(input, 1); + u64bit W02 = load_be(input, 2); + u64bit W03 = load_be(input, 3); + u64bit W04 = load_be(input, 4); + u64bit W05 = load_be(input, 5); + u64bit W06 = load_be(input, 6); + u64bit W07 = load_be(input, 7); + u64bit W08 = load_be(input, 8); + u64bit W09 = load_be(input, 9); + u64bit W10 = load_be(input, 10); + u64bit W11 = load_be(input, 11); + u64bit W12 = load_be(input, 12); + u64bit W13 = load_be(input, 13); + u64bit W14 = load_be(input, 14); + u64bit W15 = load_be(input, 15); + + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CD); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2F); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBC); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9B); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBE); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28C); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896F); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFAB); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213F); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826F); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFC); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AED); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DF); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DE); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202A); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACB); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FC); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439EC); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532B); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619C); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1E); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBA); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAE); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBC); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4C); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2A); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAEC); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 128; + } + } + +} + +} + +/* +* SHA-384 compression function +*/ +void SHA_384::compress_n(const byte input[], size_t blocks) + { + SHA2_64::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_384::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 8) + store_be(digest[i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_384::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0xCBBB9D5DC1059ED8; + digest[1] = 0x629A292A367CD507; + digest[2] = 0x9159015A3070DD17; + digest[3] = 0x152FECD8F70E5939; + digest[4] = 0x67332667FFC00B31; + digest[5] = 0x8EB44A8768581511; + digest[6] = 0xDB0C2E0D64F98FA7; + digest[7] = 0x47B5481DBEFA4FA4; + } + +/* +* SHA-512 compression function +*/ +void SHA_512::compress_n(const byte input[], size_t blocks) + { + SHA2_64::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_512::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 8) + store_be(digest[i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_512::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0x6A09E667F3BCC908; + digest[1] = 0xBB67AE8584CAA73B; + digest[2] = 0x3C6EF372FE94F82B; + digest[3] = 0xA54FF53A5F1D36F1; + digest[4] = 0x510E527FADE682D1; + digest[5] = 0x9B05688C2B3E6C1F; + digest[6] = 0x1F83D9ABFB41BD6B; + digest[7] = 0x5BE0CD19137E2179; + } + +} diff --git a/src/lib/hash/sha2_64/sha2_64.h b/src/lib/hash/sha2_64/sha2_64.h new file mode 100644 index 000000000..58b154170 --- /dev/null +++ b/src/lib/hash/sha2_64/sha2_64.h @@ -0,0 +1,59 @@ +/* +* SHA-{384,512} +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_64BIT_H__ +#define BOTAN_SHA_64BIT_H__ + +#include + +namespace Botan { + +/** +* SHA-384 +*/ +class BOTAN_DLL SHA_384 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-384"; } + size_t output_length() const { return 48; } + HashFunction* clone() const { return new SHA_384; } + + void clear(); + + SHA_384() : MDx_HashFunction(128, true, true, 16), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector digest; + }; + +/** +* SHA-512 +*/ +class BOTAN_DLL SHA_512 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-512"; } + size_t output_length() const { return 64; } + HashFunction* clone() const { return new SHA_512; } + + void clear(); + + SHA_512() : MDx_HashFunction(128, true, true, 16), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + secure_vector digest; + }; + +} + +#endif diff --git a/src/lib/hash/skein/info.txt b/src/lib/hash/skein/info.txt new file mode 100644 index 000000000..89443132b --- /dev/null +++ b/src/lib/hash/skein/info.txt @@ -0,0 +1,5 @@ +define SKEIN_512 20131128 + + +alloc + diff --git a/src/lib/hash/skein/skein_512.cpp b/src/lib/hash/skein/skein_512.cpp new file mode 100644 index 000000000..9aafb1616 --- /dev/null +++ b/src/lib/hash/skein/skein_512.cpp @@ -0,0 +1,274 @@ +/* +* The Skein-512 hash function +* (C) 2009-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +enum type_code { + SKEIN_KEY = 0, + SKEIN_CONFIG = 4, + SKEIN_PERSONALIZATION = 8, + SKEIN_PUBLIC_KEY = 12, + SKEIN_KEY_IDENTIFIER = 16, + SKEIN_NONCE = 20, + SKEIN_MSG = 48, + SKEIN_OUTPUT = 63 +}; + +void ubi_512(secure_vector& H, + secure_vector& T, + const byte msg[], size_t msg_len) + { + do + { + const size_t to_proc = std::min(msg_len, 64); + T[0] += to_proc; + + u64bit M[8] = { 0 }; + + load_le(M, msg, to_proc / 8); + + if(to_proc % 8) + { + for(size_t j = 0; j != to_proc % 8; ++j) + M[to_proc/8] |= static_cast(msg[8*(to_proc/8)+j]) << (8*j); + } + + H[8] = H[0] ^ H[1] ^ H[2] ^ H[3] ^ + H[4] ^ H[5] ^ H[6] ^ H[7] ^ 0x1BD11BDAA9FC1A22; + + T[2] = T[0] ^ T[1]; + + u64bit X0 = M[0] + H[0]; + u64bit X1 = M[1] + H[1]; + u64bit X2 = M[2] + H[2]; + u64bit X3 = M[3] + H[3]; + u64bit X4 = M[4] + H[4]; + u64bit X5 = M[5] + H[5] + T[0]; + u64bit X6 = M[6] + H[6] + T[1]; + u64bit X7 = M[7] + H[7]; + +#define THREEFISH_ROUND(X1,X2,X3,X4,X5,X6,X7,X8,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X1 += X2; X2 = rotate_left(X2, ROT1) ^ X1; \ + X3 += X4; X4 = rotate_left(X4, ROT2) ^ X3; \ + X5 += X6; X6 = rotate_left(X6, ROT3) ^ X5; \ + X7 += X8; X8 = rotate_left(X8, ROT4) ^ X7; \ + } while(0); + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 += H[(r ) % 9]; \ + X1 += H[(r+1) % 9]; \ + X2 += H[(r+2) % 9]; \ + X3 += H[(r+3) % 9]; \ + X4 += H[(r+4) % 9]; \ + X5 += H[(r+5) % 9] + T[(r ) % 3]; \ + X6 += H[(r+6) % 9] + T[(r+1) % 3]; \ + X7 += H[(r+7) % 9] + (r); \ + } while(0); + +#define THREEFISH_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7, 46,36,19,37); \ + THREEFISH_ROUND(X2,X1,X4,X7,X6,X5,X0,X3, 33,27,14,42); \ + THREEFISH_ROUND(X4,X1,X6,X3,X0,X5,X2,X7, 17,49,36,39); \ + THREEFISH_ROUND(X6,X1,X0,X7,X2,X5,X4,X3, 44, 9,54,56); \ + \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7, 39,30,34,24); \ + THREEFISH_ROUND(X2,X1,X4,X7,X6,X5,X0,X3, 13,50,10,17); \ + THREEFISH_ROUND(X4,X1,X6,X3,X0,X5,X2,X7, 25,29,39,43); \ + THREEFISH_ROUND(X6,X1,X0,X7,X2,X5,X4,X3, 8,35,56,22); \ + \ + THREEFISH_INJECT_KEY(R2); \ + } while(0); + + THREEFISH_8_ROUNDS(1,2); + THREEFISH_8_ROUNDS(3,4); + THREEFISH_8_ROUNDS(5,6); + THREEFISH_8_ROUNDS(7,8); + THREEFISH_8_ROUNDS(9,10); + THREEFISH_8_ROUNDS(11,12); + THREEFISH_8_ROUNDS(13,14); + THREEFISH_8_ROUNDS(15,16); + THREEFISH_8_ROUNDS(17,18); + + // message feed forward + H[0] = X0 ^ M[0]; + H[1] = X1 ^ M[1]; + H[2] = X2 ^ M[2]; + H[3] = X3 ^ M[3]; + H[4] = X4 ^ M[4]; + H[5] = X5 ^ M[5]; + H[6] = X6 ^ M[6]; + H[7] = X7 ^ M[7]; + + // clear first flag if set + T[1] &= ~(static_cast(1) << 62); + + msg_len -= to_proc; + msg += to_proc; + } while(msg_len); + } + +void reset_tweak(secure_vector& T, + type_code type, bool final) + { + T[0] = 0; + + T[1] = (static_cast(type) << 56) | + (static_cast(1) << 62) | + (static_cast(final) << 63); + } + +void initial_block(secure_vector& H, + secure_vector& T, + size_t output_bits, + const std::string& personalization) + { + zeroise(H); + + // ASCII("SHA3") followed by version (0x0001) code + byte config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 }; + store_le(u32bit(output_bits), config_str + 8); + + reset_tweak(T, SKEIN_CONFIG, true); + ubi_512(H, T, config_str, sizeof(config_str)); + + if(personalization != "") + { + /* + This is a limitation of this implementation, and not of the + algorithm specification. Could be fixed relatively easily, but + doesn't seem worth the trouble. + */ + if(personalization.length() > 64) + throw Invalid_Argument("Skein personalization must be <= 64 bytes"); + + const byte* bits = reinterpret_cast(personalization.data()); + + reset_tweak(T, SKEIN_PERSONALIZATION, true); + ubi_512(H, T, bits, personalization.length()); + } + + reset_tweak(T, SKEIN_MSG, false); + } + +} + +Skein_512::Skein_512(size_t arg_output_bits, + const std::string& arg_personalization) : + personalization(arg_personalization), + output_bits(arg_output_bits), + H(9), T(3), buffer(64), buf_pos(0) + { + if(output_bits == 0 || output_bits % 8 != 0 || output_bits > 64*1024) + throw Invalid_Argument("Bad output bits size for Skein-512"); + + initial_block(H, T, output_bits, personalization); + } + +std::string Skein_512::name() const + { + if(personalization != "") + return "Skein-512(" + std::to_string(output_bits) + "," + + personalization + ")"; + return "Skein-512(" + std::to_string(output_bits) + ")"; + } + +HashFunction* Skein_512::clone() const + { + return new Skein_512(output_bits, personalization); + } + +void Skein_512::clear() + { + zeroise(H); + zeroise(T); + zeroise(buffer); + buf_pos = 0; + } + +void Skein_512::add_data(const byte input[], size_t length) + { + if(length == 0) + return; + + if(buf_pos) + { + buffer_insert(buffer, buf_pos, input, length); + if(buf_pos + length > 64) + { + ubi_512(H, T, &buffer[0], buffer.size()); + + input += (64 - buf_pos); + length -= (64 - buf_pos); + buf_pos = 0; + } + } + + const size_t full_blocks = (length - 1) / 64; + + if(full_blocks) + ubi_512(H, T, input, 64*full_blocks); + + length -= full_blocks * 64; + + buffer_insert(buffer, buf_pos, input + full_blocks * 64, length); + buf_pos += length; + } + +void Skein_512::final_result(byte out[]) + { + T[1] |= (static_cast(1) << 63); // final block flag + + for(size_t i = buf_pos; i != buffer.size(); ++i) + buffer[i] = 0; + + ubi_512(H, T, &buffer[0], buf_pos); + + byte counter[8] = { 0 }; + + size_t out_bytes = output_bits / 8; + + secure_vector H_out(9); + + while(out_bytes) + { + const size_t to_proc = std::min(out_bytes, 64); + + copy_mem(&H_out[0], &H[0], 8); + + reset_tweak(T, SKEIN_OUTPUT, true); + ubi_512(H_out, T, counter, sizeof(counter)); + + for(size_t i = 0; i != to_proc; ++i) + out[i] = get_byte(7-i%8, H_out[i/8]); + + out_bytes -= to_proc; + out += to_proc; + + for(size_t i = 0; i != sizeof(counter); ++i) + if(++counter[i]) + break; + } + + buf_pos = 0; + initial_block(H, T, output_bits, personalization); + } + +} diff --git a/src/lib/hash/skein/skein_512.h b/src/lib/hash/skein/skein_512.h new file mode 100644 index 000000000..e0abc06ae --- /dev/null +++ b/src/lib/hash/skein/skein_512.h @@ -0,0 +1,52 @@ +/* +* The Skein-512 hash function +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SKEIN_512_H__ +#define BOTAN_SKEIN_512_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Skein-512, a SHA-3 candidate +*/ +class BOTAN_DLL Skein_512 : public HashFunction + { + public: + /** + * @param output_bits the output size of Skein in bits + * @param personalization is a string that will paramaterize the + * hash output + */ + Skein_512(size_t output_bits = 512, + const std::string& personalization = ""); + + size_t hash_block_size() const { return 64; } + size_t output_length() const { return output_bits / 8; } + + HashFunction* clone() const; + std::string name() const; + void clear(); + private: + void add_data(const byte input[], size_t length); + void final_result(byte out[]); + + std::string personalization; + size_t output_bits; + + secure_vector H; + secure_vector T; + secure_vector buffer; + size_t buf_pos; + }; + +} + +#endif diff --git a/src/lib/hash/tiger/info.txt b/src/lib/hash/tiger/info.txt new file mode 100644 index 000000000..773f2b037 --- /dev/null +++ b/src/lib/hash/tiger/info.txt @@ -0,0 +1,5 @@ +define TIGER 20131128 + + +mdx_hash + diff --git a/src/lib/hash/tiger/tig_tab.cpp b/src/lib/hash/tiger/tig_tab.cpp new file mode 100644 index 000000000..b76501d74 --- /dev/null +++ b/src/lib/hash/tiger/tig_tab.cpp @@ -0,0 +1,364 @@ +/* +* S-Box Tables for Tiger +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const u64bit Tiger::SBOX1[256] = { + 0x02AAB17CF7E90C5E, 0xAC424B03E243A8EC, 0x72CD5BE30DD5FCD3, + 0x6D019B93F6F97F3A, 0xCD9978FFD21F9193, 0x7573A1C9708029E2, + 0xB164326B922A83C3, 0x46883EEE04915870, 0xEAACE3057103ECE6, + 0xC54169B808A3535C, 0x4CE754918DDEC47C, 0x0AA2F4DFDC0DF40C, + 0x10B76F18A74DBEFA, 0xC6CCB6235AD1AB6A, 0x13726121572FE2FF, + 0x1A488C6F199D921E, 0x4BC9F9F4DA0007CA, 0x26F5E6F6E85241C7, + 0x859079DBEA5947B6, 0x4F1885C5C99E8C92, 0xD78E761EA96F864B, + 0x8E36428C52B5C17D, 0x69CF6827373063C1, 0xB607C93D9BB4C56E, + 0x7D820E760E76B5EA, 0x645C9CC6F07FDC42, 0xBF38A078243342E0, + 0x5F6B343C9D2E7D04, 0xF2C28AEB600B0EC6, 0x6C0ED85F7254BCAC, + 0x71592281A4DB4FE5, 0x1967FA69CE0FED9F, 0xFD5293F8B96545DB, + 0xC879E9D7F2A7600B, 0x860248920193194E, 0xA4F9533B2D9CC0B3, + 0x9053836C15957613, 0xDB6DCF8AFC357BF1, 0x18BEEA7A7A370F57, + 0x037117CA50B99066, 0x6AB30A9774424A35, 0xF4E92F02E325249B, + 0x7739DB07061CCAE1, 0xD8F3B49CECA42A05, 0xBD56BE3F51382F73, + 0x45FAED5843B0BB28, 0x1C813D5C11BF1F83, 0x8AF0E4B6D75FA169, + 0x33EE18A487AD9999, 0x3C26E8EAB1C94410, 0xB510102BC0A822F9, + 0x141EEF310CE6123B, 0xFC65B90059DDB154, 0xE0158640C5E0E607, + 0x884E079826C3A3CF, 0x930D0D9523C535FD, 0x35638D754E9A2B00, + 0x4085FCCF40469DD5, 0xC4B17AD28BE23A4C, 0xCAB2F0FC6A3E6A2E, + 0x2860971A6B943FCD, 0x3DDE6EE212E30446, 0x6222F32AE01765AE, + 0x5D550BB5478308FE, 0xA9EFA98DA0EDA22A, 0xC351A71686C40DA7, + 0x1105586D9C867C84, 0xDCFFEE85FDA22853, 0xCCFBD0262C5EEF76, + 0xBAF294CB8990D201, 0xE69464F52AFAD975, 0x94B013AFDF133E14, + 0x06A7D1A32823C958, 0x6F95FE5130F61119, 0xD92AB34E462C06C0, + 0xED7BDE33887C71D2, 0x79746D6E6518393E, 0x5BA419385D713329, + 0x7C1BA6B948A97564, 0x31987C197BFDAC67, 0xDE6C23C44B053D02, + 0x581C49FED002D64D, 0xDD474D6338261571, 0xAA4546C3E473D062, + 0x928FCE349455F860, 0x48161BBACAAB94D9, 0x63912430770E6F68, + 0x6EC8A5E602C6641C, 0x87282515337DDD2B, 0x2CDA6B42034B701B, + 0xB03D37C181CB096D, 0xE108438266C71C6F, 0x2B3180C7EB51B255, + 0xDF92B82F96C08BBC, 0x5C68C8C0A632F3BA, 0x5504CC861C3D0556, + 0xABBFA4E55FB26B8F, 0x41848B0AB3BACEB4, 0xB334A273AA445D32, + 0xBCA696F0A85AD881, 0x24F6EC65B528D56C, 0x0CE1512E90F4524A, + 0x4E9DD79D5506D35A, 0x258905FAC6CE9779, 0x2019295B3E109B33, + 0xF8A9478B73A054CC, 0x2924F2F934417EB0, 0x3993357D536D1BC4, + 0x38A81AC21DB6FF8B, 0x47C4FBF17D6016BF, 0x1E0FAADD7667E3F5, + 0x7ABCFF62938BEB96, 0xA78DAD948FC179C9, 0x8F1F98B72911E50D, + 0x61E48EAE27121A91, 0x4D62F7AD31859808, 0xECEBA345EF5CEAEB, + 0xF5CEB25EBC9684CE, 0xF633E20CB7F76221, 0xA32CDF06AB8293E4, + 0x985A202CA5EE2CA4, 0xCF0B8447CC8A8FB1, 0x9F765244979859A3, + 0xA8D516B1A1240017, 0x0BD7BA3EBB5DC726, 0xE54BCA55B86ADB39, + 0x1D7A3AFD6C478063, 0x519EC608E7669EDD, 0x0E5715A2D149AA23, + 0x177D4571848FF194, 0xEEB55F3241014C22, 0x0F5E5CA13A6E2EC2, + 0x8029927B75F5C361, 0xAD139FABC3D6E436, 0x0D5DF1A94CCF402F, + 0x3E8BD948BEA5DFC8, 0xA5A0D357BD3FF77E, 0xA2D12E251F74F645, + 0x66FD9E525E81A082, 0x2E0C90CE7F687A49, 0xC2E8BCBEBA973BC5, + 0x000001BCE509745F, 0x423777BBE6DAB3D6, 0xD1661C7EAEF06EB5, + 0xA1781F354DAACFD8, 0x2D11284A2B16AFFC, 0xF1FC4F67FA891D1F, + 0x73ECC25DCB920ADA, 0xAE610C22C2A12651, 0x96E0A810D356B78A, + 0x5A9A381F2FE7870F, 0xD5AD62EDE94E5530, 0xD225E5E8368D1427, + 0x65977B70C7AF4631, 0x99F889B2DE39D74F, 0x233F30BF54E1D143, + 0x9A9675D3D9A63C97, 0x5470554FF334F9A8, 0x166ACB744A4F5688, + 0x70C74CAAB2E4AEAD, 0xF0D091646F294D12, 0x57B82A89684031D1, + 0xEFD95A5A61BE0B6B, 0x2FBD12E969F2F29A, 0x9BD37013FEFF9FE8, + 0x3F9B0404D6085A06, 0x4940C1F3166CFE15, 0x09542C4DCDF3DEFB, + 0xB4C5218385CD5CE3, 0xC935B7DC4462A641, 0x3417F8A68ED3B63F, + 0xB80959295B215B40, 0xF99CDAEF3B8C8572, 0x018C0614F8FCB95D, + 0x1B14ACCD1A3ACDF3, 0x84D471F200BB732D, 0xC1A3110E95E8DA16, + 0x430A7220BF1A82B8, 0xB77E090D39DF210E, 0x5EF4BD9F3CD05E9D, + 0x9D4FF6DA7E57A444, 0xDA1D60E183D4A5F8, 0xB287C38417998E47, + 0xFE3EDC121BB31886, 0xC7FE3CCC980CCBEF, 0xE46FB590189BFD03, + 0x3732FD469A4C57DC, 0x7EF700A07CF1AD65, 0x59C64468A31D8859, + 0x762FB0B4D45B61F6, 0x155BAED099047718, 0x68755E4C3D50BAA6, + 0xE9214E7F22D8B4DF, 0x2ADDBF532EAC95F4, 0x32AE3909B4BD0109, + 0x834DF537B08E3450, 0xFA209DA84220728D, 0x9E691D9B9EFE23F7, + 0x0446D288C4AE8D7F, 0x7B4CC524E169785B, 0x21D87F0135CA1385, + 0xCEBB400F137B8AA5, 0x272E2B66580796BE, 0x3612264125C2B0DE, + 0x057702BDAD1EFBB2, 0xD4BABB8EACF84BE9, 0x91583139641BC67B, + 0x8BDC2DE08036E024, 0x603C8156F49F68ED, 0xF7D236F7DBEF5111, + 0x9727C4598AD21E80, 0xA08A0896670A5FD7, 0xCB4A8F4309EBA9CB, + 0x81AF564B0F7036A1, 0xC0B99AA778199ABD, 0x959F1EC83FC8E952, + 0x8C505077794A81B9, 0x3ACAAF8F056338F0, 0x07B43F50627A6778, + 0x4A44AB49F5ECCC77, 0x3BC3D6E4B679EE98, 0x9CC0D4D1CF14108C, + 0x4406C00B206BC8A0, 0x82A18854C8D72D89, 0x67E366B35C3C432C, + 0xB923DD61102B37F2, 0x56AB2779D884271D, 0xBE83E1B0FF1525AF, + 0xFB7C65D4217E49A9, 0x6BDBE0E76D48E7D4, 0x08DF828745D9179E, + 0x22EA6A9ADD53BD34, 0xE36E141C5622200A, 0x7F805D1B8CB750EE, + 0xAFE5C7A59F58E837, 0xE27F996A4FB1C23C, 0xD3867DFB0775F0D0, + 0xD0E673DE6E88891A, 0x123AEB9EAFB86C25, 0x30F1D5D5C145B895, + 0xBB434A2DEE7269E7, 0x78CB67ECF931FA38, 0xF33B0372323BBF9C, + 0x52D66336FB279C74, 0x505F33AC0AFB4EAA, 0xE8A5CD99A2CCE187, + 0x534974801E2D30BB, 0x8D2D5711D5876D90, 0x1F1A412891BC038E, + 0xD6E2E71D82E56648, 0x74036C3A497732B7, 0x89B67ED96361F5AB, + 0xFFED95D8F1EA02A2, 0xE72B3BD61464D43D, 0xA6300F170BDC4820, + 0xEBC18760ED78A77A }; + +const u64bit Tiger::SBOX2[256] = { + 0xE6A6BE5A05A12138, 0xB5A122A5B4F87C98, 0x563C6089140B6990, + 0x4C46CB2E391F5DD5, 0xD932ADDBC9B79434, 0x08EA70E42015AFF5, + 0xD765A6673E478CF1, 0xC4FB757EAB278D99, 0xDF11C6862D6E0692, + 0xDDEB84F10D7F3B16, 0x6F2EF604A665EA04, 0x4A8E0F0FF0E0DFB3, + 0xA5EDEEF83DBCBA51, 0xFC4F0A2A0EA4371E, 0xE83E1DA85CB38429, + 0xDC8FF882BA1B1CE2, 0xCD45505E8353E80D, 0x18D19A00D4DB0717, + 0x34A0CFEDA5F38101, 0x0BE77E518887CAF2, 0x1E341438B3C45136, + 0xE05797F49089CCF9, 0xFFD23F9DF2591D14, 0x543DDA228595C5CD, + 0x661F81FD99052A33, 0x8736E641DB0F7B76, 0x15227725418E5307, + 0xE25F7F46162EB2FA, 0x48A8B2126C13D9FE, 0xAFDC541792E76EEA, + 0x03D912BFC6D1898F, 0x31B1AAFA1B83F51B, 0xF1AC2796E42AB7D9, + 0x40A3A7D7FCD2EBAC, 0x1056136D0AFBBCC5, 0x7889E1DD9A6D0C85, + 0xD33525782A7974AA, 0xA7E25D09078AC09B, 0xBD4138B3EAC6EDD0, + 0x920ABFBE71EB9E70, 0xA2A5D0F54FC2625C, 0xC054E36B0B1290A3, + 0xF6DD59FF62FE932B, 0x3537354511A8AC7D, 0xCA845E9172FADCD4, + 0x84F82B60329D20DC, 0x79C62CE1CD672F18, 0x8B09A2ADD124642C, + 0xD0C1E96A19D9E726, 0x5A786A9B4BA9500C, 0x0E020336634C43F3, + 0xC17B474AEB66D822, 0x6A731AE3EC9BAAC2, 0x8226667AE0840258, + 0x67D4567691CAECA5, 0x1D94155C4875ADB5, 0x6D00FD985B813FDF, + 0x51286EFCB774CD06, 0x5E8834471FA744AF, 0xF72CA0AEE761AE2E, + 0xBE40E4CDAEE8E09A, 0xE9970BBB5118F665, 0x726E4BEB33DF1964, + 0x703B000729199762, 0x4631D816F5EF30A7, 0xB880B5B51504A6BE, + 0x641793C37ED84B6C, 0x7B21ED77F6E97D96, 0x776306312EF96B73, + 0xAE528948E86FF3F4, 0x53DBD7F286A3F8F8, 0x16CADCE74CFC1063, + 0x005C19BDFA52C6DD, 0x68868F5D64D46AD3, 0x3A9D512CCF1E186A, + 0x367E62C2385660AE, 0xE359E7EA77DCB1D7, 0x526C0773749ABE6E, + 0x735AE5F9D09F734B, 0x493FC7CC8A558BA8, 0xB0B9C1533041AB45, + 0x321958BA470A59BD, 0x852DB00B5F46C393, 0x91209B2BD336B0E5, + 0x6E604F7D659EF19F, 0xB99A8AE2782CCB24, 0xCCF52AB6C814C4C7, + 0x4727D9AFBE11727B, 0x7E950D0C0121B34D, 0x756F435670AD471F, + 0xF5ADD442615A6849, 0x4E87E09980B9957A, 0x2ACFA1DF50AEE355, + 0xD898263AFD2FD556, 0xC8F4924DD80C8FD6, 0xCF99CA3D754A173A, + 0xFE477BACAF91BF3C, 0xED5371F6D690C12D, 0x831A5C285E687094, + 0xC5D3C90A3708A0A4, 0x0F7F903717D06580, 0x19F9BB13B8FDF27F, + 0xB1BD6F1B4D502843, 0x1C761BA38FFF4012, 0x0D1530C4E2E21F3B, + 0x8943CE69A7372C8A, 0xE5184E11FEB5CE66, 0x618BDB80BD736621, + 0x7D29BAD68B574D0B, 0x81BB613E25E6FE5B, 0x071C9C10BC07913F, + 0xC7BEEB7909AC2D97, 0xC3E58D353BC5D757, 0xEB017892F38F61E8, + 0xD4EFFB9C9B1CC21A, 0x99727D26F494F7AB, 0xA3E063A2956B3E03, + 0x9D4A8B9A4AA09C30, 0x3F6AB7D500090FB4, 0x9CC0F2A057268AC0, + 0x3DEE9D2DEDBF42D1, 0x330F49C87960A972, 0xC6B2720287421B41, + 0x0AC59EC07C00369C, 0xEF4EAC49CB353425, 0xF450244EEF0129D8, + 0x8ACC46E5CAF4DEB6, 0x2FFEAB63989263F7, 0x8F7CB9FE5D7A4578, + 0x5BD8F7644E634635, 0x427A7315BF2DC900, 0x17D0C4AA2125261C, + 0x3992486C93518E50, 0xB4CBFEE0A2D7D4C3, 0x7C75D6202C5DDD8D, + 0xDBC295D8E35B6C61, 0x60B369D302032B19, 0xCE42685FDCE44132, + 0x06F3DDB9DDF65610, 0x8EA4D21DB5E148F0, 0x20B0FCE62FCD496F, + 0x2C1B912358B0EE31, 0xB28317B818F5A308, 0xA89C1E189CA6D2CF, + 0x0C6B18576AAADBC8, 0xB65DEAA91299FAE3, 0xFB2B794B7F1027E7, + 0x04E4317F443B5BEB, 0x4B852D325939D0A6, 0xD5AE6BEEFB207FFC, + 0x309682B281C7D374, 0xBAE309A194C3B475, 0x8CC3F97B13B49F05, + 0x98A9422FF8293967, 0x244B16B01076FF7C, 0xF8BF571C663D67EE, + 0x1F0D6758EEE30DA1, 0xC9B611D97ADEB9B7, 0xB7AFD5887B6C57A2, + 0x6290AE846B984FE1, 0x94DF4CDEACC1A5FD, 0x058A5BD1C5483AFF, + 0x63166CC142BA3C37, 0x8DB8526EB2F76F40, 0xE10880036F0D6D4E, + 0x9E0523C9971D311D, 0x45EC2824CC7CD691, 0x575B8359E62382C9, + 0xFA9E400DC4889995, 0xD1823ECB45721568, 0xDAFD983B8206082F, + 0xAA7D29082386A8CB, 0x269FCD4403B87588, 0x1B91F5F728BDD1E0, + 0xE4669F39040201F6, 0x7A1D7C218CF04ADE, 0x65623C29D79CE5CE, + 0x2368449096C00BB1, 0xAB9BF1879DA503BA, 0xBC23ECB1A458058E, + 0x9A58DF01BB401ECC, 0xA070E868A85F143D, 0x4FF188307DF2239E, + 0x14D565B41A641183, 0xEE13337452701602, 0x950E3DCF3F285E09, + 0x59930254B9C80953, 0x3BF299408930DA6D, 0xA955943F53691387, + 0xA15EDECAA9CB8784, 0x29142127352BE9A0, 0x76F0371FFF4E7AFB, + 0x0239F450274F2228, 0xBB073AF01D5E868B, 0xBFC80571C10E96C1, + 0xD267088568222E23, 0x9671A3D48E80B5B0, 0x55B5D38AE193BB81, + 0x693AE2D0A18B04B8, 0x5C48B4ECADD5335F, 0xFD743B194916A1CA, + 0x2577018134BE98C4, 0xE77987E83C54A4AD, 0x28E11014DA33E1B9, + 0x270CC59E226AA213, 0x71495F756D1A5F60, 0x9BE853FB60AFEF77, + 0xADC786A7F7443DBF, 0x0904456173B29A82, 0x58BC7A66C232BD5E, + 0xF306558C673AC8B2, 0x41F639C6B6C9772A, 0x216DEFE99FDA35DA, + 0x11640CC71C7BE615, 0x93C43694565C5527, 0xEA038E6246777839, + 0xF9ABF3CE5A3E2469, 0x741E768D0FD312D2, 0x0144B883CED652C6, + 0xC20B5A5BA33F8552, 0x1AE69633C3435A9D, 0x97A28CA4088CFDEC, + 0x8824A43C1E96F420, 0x37612FA66EEEA746, 0x6B4CB165F9CF0E5A, + 0x43AA1C06A0ABFB4A, 0x7F4DC26FF162796B, 0x6CBACC8E54ED9B0F, + 0xA6B7FFEFD2BB253E, 0x2E25BC95B0A29D4F, 0x86D6A58BDEF1388C, + 0xDED74AC576B6F054, 0x8030BDBC2B45805D, 0x3C81AF70E94D9289, + 0x3EFF6DDA9E3100DB, 0xB38DC39FDFCC8847, 0x123885528D17B87E, + 0xF2DA0ED240B1B642, 0x44CEFADCD54BF9A9, 0x1312200E433C7EE6, + 0x9FFCC84F3A78C748, 0xF0CD1F72248576BB, 0xEC6974053638CFE4, + 0x2BA7B67C0CEC4E4C, 0xAC2F4DF3E5CE32ED, 0xCB33D14326EA4C11, + 0xA4E9044CC77E58BC, 0x5F513293D934FCEF, 0x5DC9645506E55444, + 0x50DE418F317DE40A, 0x388CB31A69DDE259, 0x2DB4A83455820A86, + 0x9010A91E84711AE9, 0x4DF7F0B7B1498371, 0xD62A2EABC0977179, + 0x22FAC097AA8D5C0E }; + +const u64bit Tiger::SBOX3[256] = { + 0xF49FCC2FF1DAF39B, 0x487FD5C66FF29281, 0xE8A30667FCDCA83F, + 0x2C9B4BE3D2FCCE63, 0xDA3FF74B93FBBBC2, 0x2FA165D2FE70BA66, + 0xA103E279970E93D4, 0xBECDEC77B0E45E71, 0xCFB41E723985E497, + 0xB70AAA025EF75017, 0xD42309F03840B8E0, 0x8EFC1AD035898579, + 0x96C6920BE2B2ABC5, 0x66AF4163375A9172, 0x2174ABDCCA7127FB, + 0xB33CCEA64A72FF41, 0xF04A4933083066A5, 0x8D970ACDD7289AF5, + 0x8F96E8E031C8C25E, 0xF3FEC02276875D47, 0xEC7BF310056190DD, + 0xF5ADB0AEBB0F1491, 0x9B50F8850FD58892, 0x4975488358B74DE8, + 0xA3354FF691531C61, 0x0702BBE481D2C6EE, 0x89FB24057DEDED98, + 0xAC3075138596E902, 0x1D2D3580172772ED, 0xEB738FC28E6BC30D, + 0x5854EF8F63044326, 0x9E5C52325ADD3BBE, 0x90AA53CF325C4623, + 0xC1D24D51349DD067, 0x2051CFEEA69EA624, 0x13220F0A862E7E4F, + 0xCE39399404E04864, 0xD9C42CA47086FCB7, 0x685AD2238A03E7CC, + 0x066484B2AB2FF1DB, 0xFE9D5D70EFBF79EC, 0x5B13B9DD9C481854, + 0x15F0D475ED1509AD, 0x0BEBCD060EC79851, 0xD58C6791183AB7F8, + 0xD1187C5052F3EEE4, 0xC95D1192E54E82FF, 0x86EEA14CB9AC6CA2, + 0x3485BEB153677D5D, 0xDD191D781F8C492A, 0xF60866BAA784EBF9, + 0x518F643BA2D08C74, 0x8852E956E1087C22, 0xA768CB8DC410AE8D, + 0x38047726BFEC8E1A, 0xA67738B4CD3B45AA, 0xAD16691CEC0DDE19, + 0xC6D4319380462E07, 0xC5A5876D0BA61938, 0x16B9FA1FA58FD840, + 0x188AB1173CA74F18, 0xABDA2F98C99C021F, 0x3E0580AB134AE816, + 0x5F3B05B773645ABB, 0x2501A2BE5575F2F6, 0x1B2F74004E7E8BA9, + 0x1CD7580371E8D953, 0x7F6ED89562764E30, 0xB15926FF596F003D, + 0x9F65293DA8C5D6B9, 0x6ECEF04DD690F84C, 0x4782275FFF33AF88, + 0xE41433083F820801, 0xFD0DFE409A1AF9B5, 0x4325A3342CDB396B, + 0x8AE77E62B301B252, 0xC36F9E9F6655615A, 0x85455A2D92D32C09, + 0xF2C7DEA949477485, 0x63CFB4C133A39EBA, 0x83B040CC6EBC5462, + 0x3B9454C8FDB326B0, 0x56F56A9E87FFD78C, 0x2DC2940D99F42BC6, + 0x98F7DF096B096E2D, 0x19A6E01E3AD852BF, 0x42A99CCBDBD4B40B, + 0xA59998AF45E9C559, 0x366295E807D93186, 0x6B48181BFAA1F773, + 0x1FEC57E2157A0A1D, 0x4667446AF6201AD5, 0xE615EBCACFB0F075, + 0xB8F31F4F68290778, 0x22713ED6CE22D11E, 0x3057C1A72EC3C93B, + 0xCB46ACC37C3F1F2F, 0xDBB893FD02AAF50E, 0x331FD92E600B9FCF, + 0xA498F96148EA3AD6, 0xA8D8426E8B6A83EA, 0xA089B274B7735CDC, + 0x87F6B3731E524A11, 0x118808E5CBC96749, 0x9906E4C7B19BD394, + 0xAFED7F7E9B24A20C, 0x6509EADEEB3644A7, 0x6C1EF1D3E8EF0EDE, + 0xB9C97D43E9798FB4, 0xA2F2D784740C28A3, 0x7B8496476197566F, + 0x7A5BE3E6B65F069D, 0xF96330ED78BE6F10, 0xEEE60DE77A076A15, + 0x2B4BEE4AA08B9BD0, 0x6A56A63EC7B8894E, 0x02121359BA34FEF4, + 0x4CBF99F8283703FC, 0x398071350CAF30C8, 0xD0A77A89F017687A, + 0xF1C1A9EB9E423569, 0x8C7976282DEE8199, 0x5D1737A5DD1F7ABD, + 0x4F53433C09A9FA80, 0xFA8B0C53DF7CA1D9, 0x3FD9DCBC886CCB77, + 0xC040917CA91B4720, 0x7DD00142F9D1DCDF, 0x8476FC1D4F387B58, + 0x23F8E7C5F3316503, 0x032A2244E7E37339, 0x5C87A5D750F5A74B, + 0x082B4CC43698992E, 0xDF917BECB858F63C, 0x3270B8FC5BF86DDA, + 0x10AE72BB29B5DD76, 0x576AC94E7700362B, 0x1AD112DAC61EFB8F, + 0x691BC30EC5FAA427, 0xFF246311CC327143, 0x3142368E30E53206, + 0x71380E31E02CA396, 0x958D5C960AAD76F1, 0xF8D6F430C16DA536, + 0xC8FFD13F1BE7E1D2, 0x7578AE66004DDBE1, 0x05833F01067BE646, + 0xBB34B5AD3BFE586D, 0x095F34C9A12B97F0, 0x247AB64525D60CA8, + 0xDCDBC6F3017477D1, 0x4A2E14D4DECAD24D, 0xBDB5E6D9BE0A1EEB, + 0x2A7E70F7794301AB, 0xDEF42D8A270540FD, 0x01078EC0A34C22C1, + 0xE5DE511AF4C16387, 0x7EBB3A52BD9A330A, 0x77697857AA7D6435, + 0x004E831603AE4C32, 0xE7A21020AD78E312, 0x9D41A70C6AB420F2, + 0x28E06C18EA1141E6, 0xD2B28CBD984F6B28, 0x26B75F6C446E9D83, + 0xBA47568C4D418D7F, 0xD80BADBFE6183D8E, 0x0E206D7F5F166044, + 0xE258A43911CBCA3E, 0x723A1746B21DC0BC, 0xC7CAA854F5D7CDD3, + 0x7CAC32883D261D9C, 0x7690C26423BA942C, 0x17E55524478042B8, + 0xE0BE477656A2389F, 0x4D289B5E67AB2DA0, 0x44862B9C8FBBFD31, + 0xB47CC8049D141365, 0x822C1B362B91C793, 0x4EB14655FB13DFD8, + 0x1ECBBA0714E2A97B, 0x6143459D5CDE5F14, 0x53A8FBF1D5F0AC89, + 0x97EA04D81C5E5B00, 0x622181A8D4FDB3F3, 0xE9BCD341572A1208, + 0x1411258643CCE58A, 0x9144C5FEA4C6E0A4, 0x0D33D06565CF620F, + 0x54A48D489F219CA1, 0xC43E5EAC6D63C821, 0xA9728B3A72770DAF, + 0xD7934E7B20DF87EF, 0xE35503B61A3E86E5, 0xCAE321FBC819D504, + 0x129A50B3AC60BFA6, 0xCD5E68EA7E9FB6C3, 0xB01C90199483B1C7, + 0x3DE93CD5C295376C, 0xAED52EDF2AB9AD13, 0x2E60F512C0A07884, + 0xBC3D86A3E36210C9, 0x35269D9B163951CE, 0x0C7D6E2AD0CDB5FA, + 0x59E86297D87F5733, 0x298EF221898DB0E7, 0x55000029D1A5AA7E, + 0x8BC08AE1B5061B45, 0xC2C31C2B6C92703A, 0x94CC596BAF25EF42, + 0x0A1D73DB22540456, 0x04B6A0F9D9C4179A, 0xEFFDAFA2AE3D3C60, + 0xF7C8075BB49496C4, 0x9CC5C7141D1CD4E3, 0x78BD1638218E5534, + 0xB2F11568F850246A, 0xEDFABCFA9502BC29, 0x796CE5F2DA23051B, + 0xAAE128B0DC93537C, 0x3A493DA0EE4B29AE, 0xB5DF6B2C416895D7, + 0xFCABBD25122D7F37, 0x70810B58105DC4B1, 0xE10FDD37F7882A90, + 0x524DCAB5518A3F5C, 0x3C9E85878451255B, 0x4029828119BD34E2, + 0x74A05B6F5D3CECCB, 0xB610021542E13ECA, 0x0FF979D12F59E2AC, + 0x6037DA27E4F9CC50, 0x5E92975A0DF1847D, 0xD66DE190D3E623FE, + 0x5032D6B87B568048, 0x9A36B7CE8235216E, 0x80272A7A24F64B4A, + 0x93EFED8B8C6916F7, 0x37DDBFF44CCE1555, 0x4B95DB5D4B99BD25, + 0x92D3FDA169812FC0, 0xFB1A4A9A90660BB6, 0x730C196946A4B9B2, + 0x81E289AA7F49DA68, 0x64669A0F83B1A05F, 0x27B3FF7D9644F48B, + 0xCC6B615C8DB675B3, 0x674F20B9BCEBBE95, 0x6F31238275655982, + 0x5AE488713E45CF05, 0xBF619F9954C21157, 0xEABAC46040A8EAE9, + 0x454C6FE9F2C0C1CD, 0x419CF6496412691C, 0xD3DC3BEF265B0F70, + 0x6D0E60F5C3578A9E }; + +const u64bit Tiger::SBOX4[256] = { + 0x5B0E608526323C55, 0x1A46C1A9FA1B59F5, 0xA9E245A17C4C8FFA, + 0x65CA5159DB2955D7, 0x05DB0A76CE35AFC2, 0x81EAC77EA9113D45, + 0x528EF88AB6AC0A0D, 0xA09EA253597BE3FF, 0x430DDFB3AC48CD56, + 0xC4B3A67AF45CE46F, 0x4ECECFD8FBE2D05E, 0x3EF56F10B39935F0, + 0x0B22D6829CD619C6, 0x17FD460A74DF2069, 0x6CF8CC8E8510ED40, + 0xD6C824BF3A6ECAA7, 0x61243D581A817049, 0x048BACB6BBC163A2, + 0xD9A38AC27D44CC32, 0x7FDDFF5BAAF410AB, 0xAD6D495AA804824B, + 0xE1A6A74F2D8C9F94, 0xD4F7851235DEE8E3, 0xFD4B7F886540D893, + 0x247C20042AA4BFDA, 0x096EA1C517D1327C, 0xD56966B4361A6685, + 0x277DA5C31221057D, 0x94D59893A43ACFF7, 0x64F0C51CCDC02281, + 0x3D33BCC4FF6189DB, 0xE005CB184CE66AF1, 0xFF5CCD1D1DB99BEA, + 0xB0B854A7FE42980F, 0x7BD46A6A718D4B9F, 0xD10FA8CC22A5FD8C, + 0xD31484952BE4BD31, 0xC7FA975FCB243847, 0x4886ED1E5846C407, + 0x28CDDB791EB70B04, 0xC2B00BE2F573417F, 0x5C9590452180F877, + 0x7A6BDDFFF370EB00, 0xCE509E38D6D9D6A4, 0xEBEB0F00647FA702, + 0x1DCC06CF76606F06, 0xE4D9F28BA286FF0A, 0xD85A305DC918C262, + 0x475B1D8732225F54, 0x2D4FB51668CCB5FE, 0xA679B9D9D72BBA20, + 0x53841C0D912D43A5, 0x3B7EAA48BF12A4E8, 0x781E0E47F22F1DDF, + 0xEFF20CE60AB50973, 0x20D261D19DFFB742, 0x16A12B03062A2E39, + 0x1960EB2239650495, 0x251C16FED50EB8B8, 0x9AC0C330F826016E, + 0xED152665953E7671, 0x02D63194A6369570, 0x5074F08394B1C987, + 0x70BA598C90B25CE1, 0x794A15810B9742F6, 0x0D5925E9FCAF8C6C, + 0x3067716CD868744E, 0x910AB077E8D7731B, 0x6A61BBDB5AC42F61, + 0x93513EFBF0851567, 0xF494724B9E83E9D5, 0xE887E1985C09648D, + 0x34B1D3C675370CFD, 0xDC35E433BC0D255D, 0xD0AAB84234131BE0, + 0x08042A50B48B7EAF, 0x9997C4EE44A3AB35, 0x829A7B49201799D0, + 0x263B8307B7C54441, 0x752F95F4FD6A6CA6, 0x927217402C08C6E5, + 0x2A8AB754A795D9EE, 0xA442F7552F72943D, 0x2C31334E19781208, + 0x4FA98D7CEAEE6291, 0x55C3862F665DB309, 0xBD0610175D53B1F3, + 0x46FE6CB840413F27, 0x3FE03792DF0CFA59, 0xCFE700372EB85E8F, + 0xA7BE29E7ADBCE118, 0xE544EE5CDE8431DD, 0x8A781B1B41F1873E, + 0xA5C94C78A0D2F0E7, 0x39412E2877B60728, 0xA1265EF3AFC9A62C, + 0xBCC2770C6A2506C5, 0x3AB66DD5DCE1CE12, 0xE65499D04A675B37, + 0x7D8F523481BFD216, 0x0F6F64FCEC15F389, 0x74EFBE618B5B13C8, + 0xACDC82B714273E1D, 0xDD40BFE003199D17, 0x37E99257E7E061F8, + 0xFA52626904775AAA, 0x8BBBF63A463D56F9, 0xF0013F1543A26E64, + 0xA8307E9F879EC898, 0xCC4C27A4150177CC, 0x1B432F2CCA1D3348, + 0xDE1D1F8F9F6FA013, 0x606602A047A7DDD6, 0xD237AB64CC1CB2C7, + 0x9B938E7225FCD1D3, 0xEC4E03708E0FF476, 0xFEB2FBDA3D03C12D, + 0xAE0BCED2EE43889A, 0x22CB8923EBFB4F43, 0x69360D013CF7396D, + 0x855E3602D2D4E022, 0x073805BAD01F784C, 0x33E17A133852F546, + 0xDF4874058AC7B638, 0xBA92B29C678AA14A, 0x0CE89FC76CFAADCD, + 0x5F9D4E0908339E34, 0xF1AFE9291F5923B9, 0x6E3480F60F4A265F, + 0xEEBF3A2AB29B841C, 0xE21938A88F91B4AD, 0x57DFEFF845C6D3C3, + 0x2F006B0BF62CAAF2, 0x62F479EF6F75EE78, 0x11A55AD41C8916A9, + 0xF229D29084FED453, 0x42F1C27B16B000E6, 0x2B1F76749823C074, + 0x4B76ECA3C2745360, 0x8C98F463B91691BD, 0x14BCC93CF1ADE66A, + 0x8885213E6D458397, 0x8E177DF0274D4711, 0xB49B73B5503F2951, + 0x10168168C3F96B6B, 0x0E3D963B63CAB0AE, 0x8DFC4B5655A1DB14, + 0xF789F1356E14DE5C, 0x683E68AF4E51DAC1, 0xC9A84F9D8D4B0FD9, + 0x3691E03F52A0F9D1, 0x5ED86E46E1878E80, 0x3C711A0E99D07150, + 0x5A0865B20C4E9310, 0x56FBFC1FE4F0682E, 0xEA8D5DE3105EDF9B, + 0x71ABFDB12379187A, 0x2EB99DE1BEE77B9C, 0x21ECC0EA33CF4523, + 0x59A4D7521805C7A1, 0x3896F5EB56AE7C72, 0xAA638F3DB18F75DC, + 0x9F39358DABE9808E, 0xB7DEFA91C00B72AC, 0x6B5541FD62492D92, + 0x6DC6DEE8F92E4D5B, 0x353F57ABC4BEEA7E, 0x735769D6DA5690CE, + 0x0A234AA642391484, 0xF6F9508028F80D9D, 0xB8E319A27AB3F215, + 0x31AD9C1151341A4D, 0x773C22A57BEF5805, 0x45C7561A07968633, + 0xF913DA9E249DBE36, 0xDA652D9B78A64C68, 0x4C27A97F3BC334EF, + 0x76621220E66B17F4, 0x967743899ACD7D0B, 0xF3EE5BCAE0ED6782, + 0x409F753600C879FC, 0x06D09A39B5926DB6, 0x6F83AEB0317AC588, + 0x01E6CA4A86381F21, 0x66FF3462D19F3025, 0x72207C24DDFD3BFB, + 0x4AF6B6D3E2ECE2EB, 0x9C994DBEC7EA08DE, 0x49ACE597B09A8BC4, + 0xB38C4766CF0797BA, 0x131B9373C57C2A75, 0xB1822CCE61931E58, + 0x9D7555B909BA1C0C, 0x127FAFDD937D11D2, 0x29DA3BADC66D92E4, + 0xA2C1D57154C2ECBC, 0x58C5134D82F6FE24, 0x1C3AE3515B62274F, + 0xE907C82E01CB8126, 0xF8ED091913E37FCB, 0x3249D8F9C80046C9, + 0x80CF9BEDE388FB63, 0x1881539A116CF19E, 0x5103F3F76BD52457, + 0x15B7E6F5AE47F7A8, 0xDBD7C6DED47E9CCF, 0x44E55C410228BB1A, + 0xB647D4255EDB4E99, 0x5D11882BB8AAFC30, 0xF5098BBB29D3212A, + 0x8FB5EA14E90296B3, 0x677B942157DD025A, 0xFB58E7C0A390ACB5, + 0x89D3674C83BD4A01, 0x9E2DA4DF4BF3B93B, 0xFCC41E328CAB4829, + 0x03F38C96BA582C52, 0xCAD1BDBD7FD85DB2, 0xBBB442C16082AE83, + 0xB95FE86BA5DA9AB0, 0xB22E04673771A93F, 0x845358C9493152D8, + 0xBE2A488697B4541E, 0x95A2DC2DD38E6966, 0xC02C11AC923C852B, + 0x2388B1990DF2A87B, 0x7C8008FA1B4F37BE, 0x1F70D0C84D54E503, + 0x5490ADEC7ECE57D4, 0x002B3C27D9063A3A, 0x7EAEA3848030A2BF, + 0xC602326DED2003C0, 0x83A7287D69A94086, 0xC57A5FCB30F57A8A, + 0xB56844E479EBE779, 0xA373B40F05DCBCE9, 0xD71A786E88570EE2, + 0x879CBACDBDE8F6A0, 0x976AD1BCC164A32F, 0xAB21E25E9666D78B, + 0x901063AAE5E5C33C, 0x9818B34448698D90, 0xE36487AE3E1E8ABB, + 0xAFBDF931893BDCB4, 0x6345A0DC5FBBD519, 0x8628FE269B9465CA, + 0x1E5D01603F9C51EC, 0x4DE44006A15049B7, 0xBF6C70E5F776CBB1, + 0x411218F2EF552BED, 0xCB0C0708705A36A3, 0xE74D14754F986044, + 0xCD56D9430EA8280E, 0xC12591D7535F5065, 0xC83223F1720AEF96, + 0xC3A0396F7363A51F }; + +} diff --git a/src/lib/hash/tiger/tiger.cpp b/src/lib/hash/tiger/tiger.cpp new file mode 100644 index 000000000..57250d6f5 --- /dev/null +++ b/src/lib/hash/tiger/tiger.cpp @@ -0,0 +1,187 @@ +/* +* Tiger +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Tiger Mixing Function +*/ +inline void mix(secure_vector& X) + { + X[0] -= X[7] ^ 0xA5A5A5A5A5A5A5A5; + X[1] ^= X[0]; + X[2] += X[1]; + X[3] -= X[2] ^ ((~X[1]) << 19); + X[4] ^= X[3]; + X[5] += X[4]; + X[6] -= X[5] ^ ((~X[4]) >> 23); + X[7] ^= X[6]; + + X[0] += X[7]; + X[1] -= X[0] ^ ((~X[7]) << 19); + X[2] ^= X[1]; + X[3] += X[2]; + X[4] -= X[3] ^ ((~X[2]) >> 23); + X[5] ^= X[4]; + X[6] += X[5]; + X[7] -= X[6] ^ 0x0123456789ABCDEF; + } + +} + +/* +* Tiger Compression Function +*/ +void Tiger::compress_n(const byte input[], size_t blocks) + { + u64bit A = digest[0], B = digest[1], C = digest[2]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&X[0], input, X.size()); + + pass(A, B, C, X, 5); mix(X); + pass(C, A, B, X, 7); mix(X); + pass(B, C, A, X, 9); + + for(size_t j = 3; j != passes; ++j) + { + mix(X); + pass(A, B, C, X, 9); + u64bit T = A; A = C; C = B; B = T; + } + + A = (digest[0] ^= A); + B = digest[1] = B - digest[1]; + C = (digest[2] += C); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void Tiger::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); ++i) + output[i] = get_byte(7 - (i % 8), digest[i/8]); + } + +/* +* Tiger Pass +*/ +void Tiger::pass(u64bit& A, u64bit& B, u64bit& C, + const secure_vector& X, + byte mul) + { + C ^= X[0]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[1]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + + B ^= X[2]; + C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ + SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; + A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ + SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; + A *= mul; + + C ^= X[3]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[4]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + + B ^= X[5]; + C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ + SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; + A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ + SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; + A *= mul; + + C ^= X[6]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[7]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + } + +/* +* Clear memory of sensitive data +*/ +void Tiger::clear() + { + MDx_HashFunction::clear(); + zeroise(X); + digest[0] = 0x0123456789ABCDEF; + digest[1] = 0xFEDCBA9876543210; + digest[2] = 0xF096A5B4C3B2E187; + } + +/* +* Return the name of this type +*/ +std::string Tiger::name() const + { + return "Tiger(" + std::to_string(output_length()) + "," + + std::to_string(passes) + ")"; + } + +/* +* Tiger Constructor +*/ +Tiger::Tiger(size_t hash_len, size_t passes) : + MDx_HashFunction(64, false, false), + X(8), + digest(3), + hash_len(hash_len), + passes(passes) + { + if(output_length() != 16 && output_length() != 20 && output_length() != 24) + throw Invalid_Argument("Tiger: Illegal hash output size: " + + std::to_string(output_length())); + + if(passes < 3) + throw Invalid_Argument("Tiger: Invalid number of passes: " + + std::to_string(passes)); + clear(); + } + +} diff --git a/src/lib/hash/tiger/tiger.h b/src/lib/hash/tiger/tiger.h new file mode 100644 index 000000000..70c70958b --- /dev/null +++ b/src/lib/hash/tiger/tiger.h @@ -0,0 +1,55 @@ +/* +* Tiger +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TIGER_H__ +#define BOTAN_TIGER_H__ + +#include + +namespace Botan { + +/** +* Tiger +*/ +class BOTAN_DLL Tiger : public MDx_HashFunction + { + public: + std::string name() const; + size_t output_length() const { return hash_len; } + + HashFunction* clone() const + { + return new Tiger(output_length(), passes); + } + + void clear(); + + /** + * @param out_size specifies the output length; can be 16, 20, or 24 + * @param passes to make in the algorithm + */ + Tiger(size_t out_size = 24, size_t passes = 3); + private: + void compress_n(const byte[], size_t block); + void copy_out(byte[]); + + static void pass(u64bit& A, u64bit& B, u64bit& C, + const secure_vector& M, + byte mul); + + static const u64bit SBOX1[256]; + static const u64bit SBOX2[256]; + static const u64bit SBOX3[256]; + static const u64bit SBOX4[256]; + + secure_vector X, digest; + const size_t hash_len, passes; + }; + +} + +#endif diff --git a/src/lib/hash/whirlpool/info.txt b/src/lib/hash/whirlpool/info.txt new file mode 100644 index 000000000..8b0abc25a --- /dev/null +++ b/src/lib/hash/whirlpool/info.txt @@ -0,0 +1,5 @@ +define WHIRLPOOL 20131128 + + +mdx_hash + diff --git a/src/lib/hash/whirlpool/whrl_tab.cpp b/src/lib/hash/whirlpool/whrl_tab.cpp new file mode 100644 index 000000000..cf670f308 --- /dev/null +++ b/src/lib/hash/whirlpool/whrl_tab.cpp @@ -0,0 +1,540 @@ +/* +* Diffusion Tables for Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const u64bit Whirlpool::C0[256] = { +0x18186018C07830D8, 0x23238C2305AF4626, 0xC6C63FC67EF991B8, 0xE8E887E8136FCDFB, +0x878726874CA113CB, 0xB8B8DAB8A9626D11, 0x0101040108050209, 0x4F4F214F426E9E0D, +0x3636D836ADEE6C9B, 0xA6A6A2A6590451FF, 0xD2D26FD2DEBDB90C, 0xF5F5F3F5FB06F70E, +0x7979F979EF80F296, 0x6F6FA16F5FCEDE30, 0x91917E91FCEF3F6D, 0x52525552AA07A4F8, +0x60609D6027FDC047, 0xBCBCCABC89766535, 0x9B9B569BACCD2B37, 0x8E8E028E048C018A, +0xA3A3B6A371155BD2, 0x0C0C300C603C186C, 0x7B7BF17BFF8AF684, 0x3535D435B5E16A80, +0x1D1D741DE8693AF5, 0xE0E0A7E05347DDB3, 0xD7D77BD7F6ACB321, 0xC2C22FC25EED999C, +0x2E2EB82E6D965C43, 0x4B4B314B627A9629, 0xFEFEDFFEA321E15D, 0x575741578216AED5, +0x15155415A8412ABD, 0x7777C1779FB6EEE8, 0x3737DC37A5EB6E92, 0xE5E5B3E57B56D79E, +0x9F9F469F8CD92313, 0xF0F0E7F0D317FD23, 0x4A4A354A6A7F9420, 0xDADA4FDA9E95A944, +0x58587D58FA25B0A2, 0xC9C903C906CA8FCF, 0x2929A429558D527C, 0x0A0A280A5022145A, +0xB1B1FEB1E14F7F50, 0xA0A0BAA0691A5DC9, 0x6B6BB16B7FDAD614, 0x85852E855CAB17D9, +0xBDBDCEBD8173673C, 0x5D5D695DD234BA8F, 0x1010401080502090, 0xF4F4F7F4F303F507, +0xCBCB0BCB16C08BDD, 0x3E3EF83EEDC67CD3, 0x0505140528110A2D, 0x676781671FE6CE78, +0xE4E4B7E47353D597, 0x27279C2725BB4E02, 0x4141194132588273, 0x8B8B168B2C9D0BA7, +0xA7A7A6A7510153F6, 0x7D7DE97DCF94FAB2, 0x95956E95DCFB3749, 0xD8D847D88E9FAD56, +0xFBFBCBFB8B30EB70, 0xEEEE9FEE2371C1CD, 0x7C7CED7CC791F8BB, 0x6666856617E3CC71, +0xDDDD53DDA68EA77B, 0x17175C17B84B2EAF, 0x4747014702468E45, 0x9E9E429E84DC211A, +0xCACA0FCA1EC589D4, 0x2D2DB42D75995A58, 0xBFBFC6BF9179632E, 0x07071C07381B0E3F, +0xADAD8EAD012347AC, 0x5A5A755AEA2FB4B0, 0x838336836CB51BEF, 0x3333CC3385FF66B6, +0x636391633FF2C65C, 0x02020802100A0412, 0xAAAA92AA39384993, 0x7171D971AFA8E2DE, +0xC8C807C80ECF8DC6, 0x19196419C87D32D1, 0x494939497270923B, 0xD9D943D9869AAF5F, +0xF2F2EFF2C31DF931, 0xE3E3ABE34B48DBA8, 0x5B5B715BE22AB6B9, 0x88881A8834920DBC, +0x9A9A529AA4C8293E, 0x262698262DBE4C0B, 0x3232C8328DFA64BF, 0xB0B0FAB0E94A7D59, +0xE9E983E91B6ACFF2, 0x0F0F3C0F78331E77, 0xD5D573D5E6A6B733, 0x80803A8074BA1DF4, +0xBEBEC2BE997C6127, 0xCDCD13CD26DE87EB, 0x3434D034BDE46889, 0x48483D487A759032, +0xFFFFDBFFAB24E354, 0x7A7AF57AF78FF48D, 0x90907A90F4EA3D64, 0x5F5F615FC23EBE9D, +0x202080201DA0403D, 0x6868BD6867D5D00F, 0x1A1A681AD07234CA, 0xAEAE82AE192C41B7, +0xB4B4EAB4C95E757D, 0x54544D549A19A8CE, 0x93937693ECE53B7F, 0x222288220DAA442F, +0x64648D6407E9C863, 0xF1F1E3F1DB12FF2A, 0x7373D173BFA2E6CC, 0x12124812905A2482, +0x40401D403A5D807A, 0x0808200840281048, 0xC3C32BC356E89B95, 0xECEC97EC337BC5DF, +0xDBDB4BDB9690AB4D, 0xA1A1BEA1611F5FC0, 0x8D8D0E8D1C830791, 0x3D3DF43DF5C97AC8, +0x97976697CCF1335B, 0x0000000000000000, 0xCFCF1BCF36D483F9, 0x2B2BAC2B4587566E, +0x7676C57697B3ECE1, 0x8282328264B019E6, 0xD6D67FD6FEA9B128, 0x1B1B6C1BD87736C3, +0xB5B5EEB5C15B7774, 0xAFAF86AF112943BE, 0x6A6AB56A77DFD41D, 0x50505D50BA0DA0EA, +0x45450945124C8A57, 0xF3F3EBF3CB18FB38, 0x3030C0309DF060AD, 0xEFEF9BEF2B74C3C4, +0x3F3FFC3FE5C37EDA, 0x55554955921CAAC7, 0xA2A2B2A2791059DB, 0xEAEA8FEA0365C9E9, +0x656589650FECCA6A, 0xBABAD2BAB9686903, 0x2F2FBC2F65935E4A, 0xC0C027C04EE79D8E, +0xDEDE5FDEBE81A160, 0x1C1C701CE06C38FC, 0xFDFDD3FDBB2EE746, 0x4D4D294D52649A1F, +0x92927292E4E03976, 0x7575C9758FBCEAFA, 0x06061806301E0C36, 0x8A8A128A249809AE, +0xB2B2F2B2F940794B, 0xE6E6BFE66359D185, 0x0E0E380E70361C7E, 0x1F1F7C1FF8633EE7, +0x6262956237F7C455, 0xD4D477D4EEA3B53A, 0xA8A89AA829324D81, 0x96966296C4F43152, +0xF9F9C3F99B3AEF62, 0xC5C533C566F697A3, 0x2525942535B14A10, 0x59597959F220B2AB, +0x84842A8454AE15D0, 0x7272D572B7A7E4C5, 0x3939E439D5DD72EC, 0x4C4C2D4C5A619816, +0x5E5E655ECA3BBC94, 0x7878FD78E785F09F, 0x3838E038DDD870E5, 0x8C8C0A8C14860598, +0xD1D163D1C6B2BF17, 0xA5A5AEA5410B57E4, 0xE2E2AFE2434DD9A1, 0x616199612FF8C24E, +0xB3B3F6B3F1457B42, 0x2121842115A54234, 0x9C9C4A9C94D62508, 0x1E1E781EF0663CEE, +0x4343114322528661, 0xC7C73BC776FC93B1, 0xFCFCD7FCB32BE54F, 0x0404100420140824, +0x51515951B208A2E3, 0x99995E99BCC72F25, 0x6D6DA96D4FC4DA22, 0x0D0D340D68391A65, +0xFAFACFFA8335E979, 0xDFDF5BDFB684A369, 0x7E7EE57ED79BFCA9, 0x242490243DB44819, +0x3B3BEC3BC5D776FE, 0xABAB96AB313D4B9A, 0xCECE1FCE3ED181F0, 0x1111441188552299, +0x8F8F068F0C890383, 0x4E4E254E4A6B9C04, 0xB7B7E6B7D1517366, 0xEBEB8BEB0B60CBE0, +0x3C3CF03CFDCC78C1, 0x81813E817CBF1FFD, 0x94946A94D4FE3540, 0xF7F7FBF7EB0CF31C, +0xB9B9DEB9A1676F18, 0x13134C13985F268B, 0x2C2CB02C7D9C5851, 0xD3D36BD3D6B8BB05, +0xE7E7BBE76B5CD38C, 0x6E6EA56E57CBDC39, 0xC4C437C46EF395AA, 0x03030C03180F061B, +0x565645568A13ACDC, 0x44440D441A49885E, 0x7F7FE17FDF9EFEA0, 0xA9A99EA921374F88, +0x2A2AA82A4D825467, 0xBBBBD6BBB16D6B0A, 0xC1C123C146E29F87, 0x53535153A202A6F1, +0xDCDC57DCAE8BA572, 0x0B0B2C0B58271653, 0x9D9D4E9D9CD32701, 0x6C6CAD6C47C1D82B, +0x3131C43195F562A4, 0x7474CD7487B9E8F3, 0xF6F6FFF6E309F115, 0x464605460A438C4C, +0xACAC8AAC092645A5, 0x89891E893C970FB5, 0x14145014A04428B4, 0xE1E1A3E15B42DFBA, +0x16165816B04E2CA6, 0x3A3AE83ACDD274F7, 0x6969B9696FD0D206, 0x09092409482D1241, +0x7070DD70A7ADE0D7, 0xB6B6E2B6D954716F, 0xD0D067D0CEB7BD1E, 0xEDED93ED3B7EC7D6, +0xCCCC17CC2EDB85E2, 0x424215422A578468, 0x98985A98B4C22D2C, 0xA4A4AAA4490E55ED, +0x2828A0285D885075, 0x5C5C6D5CDA31B886, 0xF8F8C7F8933FED6B, 0x8686228644A411C2 }; + +const u64bit Whirlpool::C1[256] = { +0xD818186018C07830, 0x2623238C2305AF46, 0xB8C6C63FC67EF991, 0xFBE8E887E8136FCD, +0xCB878726874CA113, 0x11B8B8DAB8A9626D, 0x0901010401080502, 0x0D4F4F214F426E9E, +0x9B3636D836ADEE6C, 0xFFA6A6A2A6590451, 0x0CD2D26FD2DEBDB9, 0x0EF5F5F3F5FB06F7, +0x967979F979EF80F2, 0x306F6FA16F5FCEDE, 0x6D91917E91FCEF3F, 0xF852525552AA07A4, +0x4760609D6027FDC0, 0x35BCBCCABC897665, 0x379B9B569BACCD2B, 0x8A8E8E028E048C01, +0xD2A3A3B6A371155B, 0x6C0C0C300C603C18, 0x847B7BF17BFF8AF6, 0x803535D435B5E16A, +0xF51D1D741DE8693A, 0xB3E0E0A7E05347DD, 0x21D7D77BD7F6ACB3, 0x9CC2C22FC25EED99, +0x432E2EB82E6D965C, 0x294B4B314B627A96, 0x5DFEFEDFFEA321E1, 0xD5575741578216AE, +0xBD15155415A8412A, 0xE87777C1779FB6EE, 0x923737DC37A5EB6E, 0x9EE5E5B3E57B56D7, +0x139F9F469F8CD923, 0x23F0F0E7F0D317FD, 0x204A4A354A6A7F94, 0x44DADA4FDA9E95A9, +0xA258587D58FA25B0, 0xCFC9C903C906CA8F, 0x7C2929A429558D52, 0x5A0A0A280A502214, +0x50B1B1FEB1E14F7F, 0xC9A0A0BAA0691A5D, 0x146B6BB16B7FDAD6, 0xD985852E855CAB17, +0x3CBDBDCEBD817367, 0x8F5D5D695DD234BA, 0x9010104010805020, 0x07F4F4F7F4F303F5, +0xDDCBCB0BCB16C08B, 0xD33E3EF83EEDC67C, 0x2D0505140528110A, 0x78676781671FE6CE, +0x97E4E4B7E47353D5, 0x0227279C2725BB4E, 0x7341411941325882, 0xA78B8B168B2C9D0B, +0xF6A7A7A6A7510153, 0xB27D7DE97DCF94FA, 0x4995956E95DCFB37, 0x56D8D847D88E9FAD, +0x70FBFBCBFB8B30EB, 0xCDEEEE9FEE2371C1, 0xBB7C7CED7CC791F8, 0x716666856617E3CC, +0x7BDDDD53DDA68EA7, 0xAF17175C17B84B2E, 0x454747014702468E, 0x1A9E9E429E84DC21, +0xD4CACA0FCA1EC589, 0x582D2DB42D75995A, 0x2EBFBFC6BF917963, 0x3F07071C07381B0E, +0xACADAD8EAD012347, 0xB05A5A755AEA2FB4, 0xEF838336836CB51B, 0xB63333CC3385FF66, +0x5C636391633FF2C6, 0x1202020802100A04, 0x93AAAA92AA393849, 0xDE7171D971AFA8E2, +0xC6C8C807C80ECF8D, 0xD119196419C87D32, 0x3B49493949727092, 0x5FD9D943D9869AAF, +0x31F2F2EFF2C31DF9, 0xA8E3E3ABE34B48DB, 0xB95B5B715BE22AB6, 0xBC88881A8834920D, +0x3E9A9A529AA4C829, 0x0B262698262DBE4C, 0xBF3232C8328DFA64, 0x59B0B0FAB0E94A7D, +0xF2E9E983E91B6ACF, 0x770F0F3C0F78331E, 0x33D5D573D5E6A6B7, 0xF480803A8074BA1D, +0x27BEBEC2BE997C61, 0xEBCDCD13CD26DE87, 0x893434D034BDE468, 0x3248483D487A7590, +0x54FFFFDBFFAB24E3, 0x8D7A7AF57AF78FF4, 0x6490907A90F4EA3D, 0x9D5F5F615FC23EBE, +0x3D202080201DA040, 0x0F6868BD6867D5D0, 0xCA1A1A681AD07234, 0xB7AEAE82AE192C41, +0x7DB4B4EAB4C95E75, 0xCE54544D549A19A8, 0x7F93937693ECE53B, 0x2F222288220DAA44, +0x6364648D6407E9C8, 0x2AF1F1E3F1DB12FF, 0xCC7373D173BFA2E6, 0x8212124812905A24, +0x7A40401D403A5D80, 0x4808082008402810, 0x95C3C32BC356E89B, 0xDFECEC97EC337BC5, +0x4DDBDB4BDB9690AB, 0xC0A1A1BEA1611F5F, 0x918D8D0E8D1C8307, 0xC83D3DF43DF5C97A, +0x5B97976697CCF133, 0x0000000000000000, 0xF9CFCF1BCF36D483, 0x6E2B2BAC2B458756, +0xE17676C57697B3EC, 0xE68282328264B019, 0x28D6D67FD6FEA9B1, 0xC31B1B6C1BD87736, +0x74B5B5EEB5C15B77, 0xBEAFAF86AF112943, 0x1D6A6AB56A77DFD4, 0xEA50505D50BA0DA0, +0x5745450945124C8A, 0x38F3F3EBF3CB18FB, 0xAD3030C0309DF060, 0xC4EFEF9BEF2B74C3, +0xDA3F3FFC3FE5C37E, 0xC755554955921CAA, 0xDBA2A2B2A2791059, 0xE9EAEA8FEA0365C9, +0x6A656589650FECCA, 0x03BABAD2BAB96869, 0x4A2F2FBC2F65935E, 0x8EC0C027C04EE79D, +0x60DEDE5FDEBE81A1, 0xFC1C1C701CE06C38, 0x46FDFDD3FDBB2EE7, 0x1F4D4D294D52649A, +0x7692927292E4E039, 0xFA7575C9758FBCEA, 0x3606061806301E0C, 0xAE8A8A128A249809, +0x4BB2B2F2B2F94079, 0x85E6E6BFE66359D1, 0x7E0E0E380E70361C, 0xE71F1F7C1FF8633E, +0x556262956237F7C4, 0x3AD4D477D4EEA3B5, 0x81A8A89AA829324D, 0x5296966296C4F431, +0x62F9F9C3F99B3AEF, 0xA3C5C533C566F697, 0x102525942535B14A, 0xAB59597959F220B2, +0xD084842A8454AE15, 0xC57272D572B7A7E4, 0xEC3939E439D5DD72, 0x164C4C2D4C5A6198, +0x945E5E655ECA3BBC, 0x9F7878FD78E785F0, 0xE53838E038DDD870, 0x988C8C0A8C148605, +0x17D1D163D1C6B2BF, 0xE4A5A5AEA5410B57, 0xA1E2E2AFE2434DD9, 0x4E616199612FF8C2, +0x42B3B3F6B3F1457B, 0x342121842115A542, 0x089C9C4A9C94D625, 0xEE1E1E781EF0663C, +0x6143431143225286, 0xB1C7C73BC776FC93, 0x4FFCFCD7FCB32BE5, 0x2404041004201408, +0xE351515951B208A2, 0x2599995E99BCC72F, 0x226D6DA96D4FC4DA, 0x650D0D340D68391A, +0x79FAFACFFA8335E9, 0x69DFDF5BDFB684A3, 0xA97E7EE57ED79BFC, 0x19242490243DB448, +0xFE3B3BEC3BC5D776, 0x9AABAB96AB313D4B, 0xF0CECE1FCE3ED181, 0x9911114411885522, +0x838F8F068F0C8903, 0x044E4E254E4A6B9C, 0x66B7B7E6B7D15173, 0xE0EBEB8BEB0B60CB, +0xC13C3CF03CFDCC78, 0xFD81813E817CBF1F, 0x4094946A94D4FE35, 0x1CF7F7FBF7EB0CF3, +0x18B9B9DEB9A1676F, 0x8B13134C13985F26, 0x512C2CB02C7D9C58, 0x05D3D36BD3D6B8BB, +0x8CE7E7BBE76B5CD3, 0x396E6EA56E57CBDC, 0xAAC4C437C46EF395, 0x1B03030C03180F06, +0xDC565645568A13AC, 0x5E44440D441A4988, 0xA07F7FE17FDF9EFE, 0x88A9A99EA921374F, +0x672A2AA82A4D8254, 0x0ABBBBD6BBB16D6B, 0x87C1C123C146E29F, 0xF153535153A202A6, +0x72DCDC57DCAE8BA5, 0x530B0B2C0B582716, 0x019D9D4E9D9CD327, 0x2B6C6CAD6C47C1D8, +0xA43131C43195F562, 0xF37474CD7487B9E8, 0x15F6F6FFF6E309F1, 0x4C464605460A438C, +0xA5ACAC8AAC092645, 0xB589891E893C970F, 0xB414145014A04428, 0xBAE1E1A3E15B42DF, +0xA616165816B04E2C, 0xF73A3AE83ACDD274, 0x066969B9696FD0D2, 0x4109092409482D12, +0xD77070DD70A7ADE0, 0x6FB6B6E2B6D95471, 0x1ED0D067D0CEB7BD, 0xD6EDED93ED3B7EC7, +0xE2CCCC17CC2EDB85, 0x68424215422A5784, 0x2C98985A98B4C22D, 0xEDA4A4AAA4490E55, +0x752828A0285D8850, 0x865C5C6D5CDA31B8, 0x6BF8F8C7F8933FED, 0xC28686228644A411 }; + +const u64bit Whirlpool::C2[256] = { +0x30D818186018C078, 0x462623238C2305AF, 0x91B8C6C63FC67EF9, 0xCDFBE8E887E8136F, +0x13CB878726874CA1, 0x6D11B8B8DAB8A962, 0x0209010104010805, 0x9E0D4F4F214F426E, +0x6C9B3636D836ADEE, 0x51FFA6A6A2A65904, 0xB90CD2D26FD2DEBD, 0xF70EF5F5F3F5FB06, +0xF2967979F979EF80, 0xDE306F6FA16F5FCE, 0x3F6D91917E91FCEF, 0xA4F852525552AA07, +0xC04760609D6027FD, 0x6535BCBCCABC8976, 0x2B379B9B569BACCD, 0x018A8E8E028E048C, +0x5BD2A3A3B6A37115, 0x186C0C0C300C603C, 0xF6847B7BF17BFF8A, 0x6A803535D435B5E1, +0x3AF51D1D741DE869, 0xDDB3E0E0A7E05347, 0xB321D7D77BD7F6AC, 0x999CC2C22FC25EED, +0x5C432E2EB82E6D96, 0x96294B4B314B627A, 0xE15DFEFEDFFEA321, 0xAED5575741578216, +0x2ABD15155415A841, 0xEEE87777C1779FB6, 0x6E923737DC37A5EB, 0xD79EE5E5B3E57B56, +0x23139F9F469F8CD9, 0xFD23F0F0E7F0D317, 0x94204A4A354A6A7F, 0xA944DADA4FDA9E95, +0xB0A258587D58FA25, 0x8FCFC9C903C906CA, 0x527C2929A429558D, 0x145A0A0A280A5022, +0x7F50B1B1FEB1E14F, 0x5DC9A0A0BAA0691A, 0xD6146B6BB16B7FDA, 0x17D985852E855CAB, +0x673CBDBDCEBD8173, 0xBA8F5D5D695DD234, 0x2090101040108050, 0xF507F4F4F7F4F303, +0x8BDDCBCB0BCB16C0, 0x7CD33E3EF83EEDC6, 0x0A2D050514052811, 0xCE78676781671FE6, +0xD597E4E4B7E47353, 0x4E0227279C2725BB, 0x8273414119413258, 0x0BA78B8B168B2C9D, +0x53F6A7A7A6A75101, 0xFAB27D7DE97DCF94, 0x374995956E95DCFB, 0xAD56D8D847D88E9F, +0xEB70FBFBCBFB8B30, 0xC1CDEEEE9FEE2371, 0xF8BB7C7CED7CC791, 0xCC716666856617E3, +0xA77BDDDD53DDA68E, 0x2EAF17175C17B84B, 0x8E45474701470246, 0x211A9E9E429E84DC, +0x89D4CACA0FCA1EC5, 0x5A582D2DB42D7599, 0x632EBFBFC6BF9179, 0x0E3F07071C07381B, +0x47ACADAD8EAD0123, 0xB4B05A5A755AEA2F, 0x1BEF838336836CB5, 0x66B63333CC3385FF, +0xC65C636391633FF2, 0x041202020802100A, 0x4993AAAA92AA3938, 0xE2DE7171D971AFA8, +0x8DC6C8C807C80ECF, 0x32D119196419C87D, 0x923B494939497270, 0xAF5FD9D943D9869A, +0xF931F2F2EFF2C31D, 0xDBA8E3E3ABE34B48, 0xB6B95B5B715BE22A, 0x0DBC88881A883492, +0x293E9A9A529AA4C8, 0x4C0B262698262DBE, 0x64BF3232C8328DFA, 0x7D59B0B0FAB0E94A, +0xCFF2E9E983E91B6A, 0x1E770F0F3C0F7833, 0xB733D5D573D5E6A6, 0x1DF480803A8074BA, +0x6127BEBEC2BE997C, 0x87EBCDCD13CD26DE, 0x68893434D034BDE4, 0x903248483D487A75, +0xE354FFFFDBFFAB24, 0xF48D7A7AF57AF78F, 0x3D6490907A90F4EA, 0xBE9D5F5F615FC23E, +0x403D202080201DA0, 0xD00F6868BD6867D5, 0x34CA1A1A681AD072, 0x41B7AEAE82AE192C, +0x757DB4B4EAB4C95E, 0xA8CE54544D549A19, 0x3B7F93937693ECE5, 0x442F222288220DAA, +0xC86364648D6407E9, 0xFF2AF1F1E3F1DB12, 0xE6CC7373D173BFA2, 0x248212124812905A, +0x807A40401D403A5D, 0x1048080820084028, 0x9B95C3C32BC356E8, 0xC5DFECEC97EC337B, +0xAB4DDBDB4BDB9690, 0x5FC0A1A1BEA1611F, 0x07918D8D0E8D1C83, 0x7AC83D3DF43DF5C9, +0x335B97976697CCF1, 0x0000000000000000, 0x83F9CFCF1BCF36D4, 0x566E2B2BAC2B4587, +0xECE17676C57697B3, 0x19E68282328264B0, 0xB128D6D67FD6FEA9, 0x36C31B1B6C1BD877, +0x7774B5B5EEB5C15B, 0x43BEAFAF86AF1129, 0xD41D6A6AB56A77DF, 0xA0EA50505D50BA0D, +0x8A5745450945124C, 0xFB38F3F3EBF3CB18, 0x60AD3030C0309DF0, 0xC3C4EFEF9BEF2B74, +0x7EDA3F3FFC3FE5C3, 0xAAC755554955921C, 0x59DBA2A2B2A27910, 0xC9E9EAEA8FEA0365, +0xCA6A656589650FEC, 0x6903BABAD2BAB968, 0x5E4A2F2FBC2F6593, 0x9D8EC0C027C04EE7, +0xA160DEDE5FDEBE81, 0x38FC1C1C701CE06C, 0xE746FDFDD3FDBB2E, 0x9A1F4D4D294D5264, +0x397692927292E4E0, 0xEAFA7575C9758FBC, 0x0C3606061806301E, 0x09AE8A8A128A2498, +0x794BB2B2F2B2F940, 0xD185E6E6BFE66359, 0x1C7E0E0E380E7036, 0x3EE71F1F7C1FF863, +0xC4556262956237F7, 0xB53AD4D477D4EEA3, 0x4D81A8A89AA82932, 0x315296966296C4F4, +0xEF62F9F9C3F99B3A, 0x97A3C5C533C566F6, 0x4A102525942535B1, 0xB2AB59597959F220, +0x15D084842A8454AE, 0xE4C57272D572B7A7, 0x72EC3939E439D5DD, 0x98164C4C2D4C5A61, +0xBC945E5E655ECA3B, 0xF09F7878FD78E785, 0x70E53838E038DDD8, 0x05988C8C0A8C1486, +0xBF17D1D163D1C6B2, 0x57E4A5A5AEA5410B, 0xD9A1E2E2AFE2434D, 0xC24E616199612FF8, +0x7B42B3B3F6B3F145, 0x42342121842115A5, 0x25089C9C4A9C94D6, 0x3CEE1E1E781EF066, +0x8661434311432252, 0x93B1C7C73BC776FC, 0xE54FFCFCD7FCB32B, 0x0824040410042014, +0xA2E351515951B208, 0x2F2599995E99BCC7, 0xDA226D6DA96D4FC4, 0x1A650D0D340D6839, +0xE979FAFACFFA8335, 0xA369DFDF5BDFB684, 0xFCA97E7EE57ED79B, 0x4819242490243DB4, +0x76FE3B3BEC3BC5D7, 0x4B9AABAB96AB313D, 0x81F0CECE1FCE3ED1, 0x2299111144118855, +0x03838F8F068F0C89, 0x9C044E4E254E4A6B, 0x7366B7B7E6B7D151, 0xCBE0EBEB8BEB0B60, +0x78C13C3CF03CFDCC, 0x1FFD81813E817CBF, 0x354094946A94D4FE, 0xF31CF7F7FBF7EB0C, +0x6F18B9B9DEB9A167, 0x268B13134C13985F, 0x58512C2CB02C7D9C, 0xBB05D3D36BD3D6B8, +0xD38CE7E7BBE76B5C, 0xDC396E6EA56E57CB, 0x95AAC4C437C46EF3, 0x061B03030C03180F, +0xACDC565645568A13, 0x885E44440D441A49, 0xFEA07F7FE17FDF9E, 0x4F88A9A99EA92137, +0x54672A2AA82A4D82, 0x6B0ABBBBD6BBB16D, 0x9F87C1C123C146E2, 0xA6F153535153A202, +0xA572DCDC57DCAE8B, 0x16530B0B2C0B5827, 0x27019D9D4E9D9CD3, 0xD82B6C6CAD6C47C1, +0x62A43131C43195F5, 0xE8F37474CD7487B9, 0xF115F6F6FFF6E309, 0x8C4C464605460A43, +0x45A5ACAC8AAC0926, 0x0FB589891E893C97, 0x28B414145014A044, 0xDFBAE1E1A3E15B42, +0x2CA616165816B04E, 0x74F73A3AE83ACDD2, 0xD2066969B9696FD0, 0x124109092409482D, +0xE0D77070DD70A7AD, 0x716FB6B6E2B6D954, 0xBD1ED0D067D0CEB7, 0xC7D6EDED93ED3B7E, +0x85E2CCCC17CC2EDB, 0x8468424215422A57, 0x2D2C98985A98B4C2, 0x55EDA4A4AAA4490E, +0x50752828A0285D88, 0xB8865C5C6D5CDA31, 0xED6BF8F8C7F8933F, 0x11C28686228644A4 }; + +const u64bit Whirlpool::C3[256] = { +0x7830D818186018C0, 0xAF462623238C2305, 0xF991B8C6C63FC67E, 0x6FCDFBE8E887E813, +0xA113CB878726874C, 0x626D11B8B8DAB8A9, 0x0502090101040108, 0x6E9E0D4F4F214F42, +0xEE6C9B3636D836AD, 0x0451FFA6A6A2A659, 0xBDB90CD2D26FD2DE, 0x06F70EF5F5F3F5FB, +0x80F2967979F979EF, 0xCEDE306F6FA16F5F, 0xEF3F6D91917E91FC, 0x07A4F852525552AA, +0xFDC04760609D6027, 0x766535BCBCCABC89, 0xCD2B379B9B569BAC, 0x8C018A8E8E028E04, +0x155BD2A3A3B6A371, 0x3C186C0C0C300C60, 0x8AF6847B7BF17BFF, 0xE16A803535D435B5, +0x693AF51D1D741DE8, 0x47DDB3E0E0A7E053, 0xACB321D7D77BD7F6, 0xED999CC2C22FC25E, +0x965C432E2EB82E6D, 0x7A96294B4B314B62, 0x21E15DFEFEDFFEA3, 0x16AED55757415782, +0x412ABD15155415A8, 0xB6EEE87777C1779F, 0xEB6E923737DC37A5, 0x56D79EE5E5B3E57B, +0xD923139F9F469F8C, 0x17FD23F0F0E7F0D3, 0x7F94204A4A354A6A, 0x95A944DADA4FDA9E, +0x25B0A258587D58FA, 0xCA8FCFC9C903C906, 0x8D527C2929A42955, 0x22145A0A0A280A50, +0x4F7F50B1B1FEB1E1, 0x1A5DC9A0A0BAA069, 0xDAD6146B6BB16B7F, 0xAB17D985852E855C, +0x73673CBDBDCEBD81, 0x34BA8F5D5D695DD2, 0x5020901010401080, 0x03F507F4F4F7F4F3, +0xC08BDDCBCB0BCB16, 0xC67CD33E3EF83EED, 0x110A2D0505140528, 0xE6CE78676781671F, +0x53D597E4E4B7E473, 0xBB4E0227279C2725, 0x5882734141194132, 0x9D0BA78B8B168B2C, +0x0153F6A7A7A6A751, 0x94FAB27D7DE97DCF, 0xFB374995956E95DC, 0x9FAD56D8D847D88E, +0x30EB70FBFBCBFB8B, 0x71C1CDEEEE9FEE23, 0x91F8BB7C7CED7CC7, 0xE3CC716666856617, +0x8EA77BDDDD53DDA6, 0x4B2EAF17175C17B8, 0x468E454747014702, 0xDC211A9E9E429E84, +0xC589D4CACA0FCA1E, 0x995A582D2DB42D75, 0x79632EBFBFC6BF91, 0x1B0E3F07071C0738, +0x2347ACADAD8EAD01, 0x2FB4B05A5A755AEA, 0xB51BEF838336836C, 0xFF66B63333CC3385, +0xF2C65C636391633F, 0x0A04120202080210, 0x384993AAAA92AA39, 0xA8E2DE7171D971AF, +0xCF8DC6C8C807C80E, 0x7D32D119196419C8, 0x70923B4949394972, 0x9AAF5FD9D943D986, +0x1DF931F2F2EFF2C3, 0x48DBA8E3E3ABE34B, 0x2AB6B95B5B715BE2, 0x920DBC88881A8834, +0xC8293E9A9A529AA4, 0xBE4C0B262698262D, 0xFA64BF3232C8328D, 0x4A7D59B0B0FAB0E9, +0x6ACFF2E9E983E91B, 0x331E770F0F3C0F78, 0xA6B733D5D573D5E6, 0xBA1DF480803A8074, +0x7C6127BEBEC2BE99, 0xDE87EBCDCD13CD26, 0xE468893434D034BD, 0x75903248483D487A, +0x24E354FFFFDBFFAB, 0x8FF48D7A7AF57AF7, 0xEA3D6490907A90F4, 0x3EBE9D5F5F615FC2, +0xA0403D202080201D, 0xD5D00F6868BD6867, 0x7234CA1A1A681AD0, 0x2C41B7AEAE82AE19, +0x5E757DB4B4EAB4C9, 0x19A8CE54544D549A, 0xE53B7F93937693EC, 0xAA442F222288220D, +0xE9C86364648D6407, 0x12FF2AF1F1E3F1DB, 0xA2E6CC7373D173BF, 0x5A24821212481290, +0x5D807A40401D403A, 0x2810480808200840, 0xE89B95C3C32BC356, 0x7BC5DFECEC97EC33, +0x90AB4DDBDB4BDB96, 0x1F5FC0A1A1BEA161, 0x8307918D8D0E8D1C, 0xC97AC83D3DF43DF5, +0xF1335B97976697CC, 0x0000000000000000, 0xD483F9CFCF1BCF36, 0x87566E2B2BAC2B45, +0xB3ECE17676C57697, 0xB019E68282328264, 0xA9B128D6D67FD6FE, 0x7736C31B1B6C1BD8, +0x5B7774B5B5EEB5C1, 0x2943BEAFAF86AF11, 0xDFD41D6A6AB56A77, 0x0DA0EA50505D50BA, +0x4C8A574545094512, 0x18FB38F3F3EBF3CB, 0xF060AD3030C0309D, 0x74C3C4EFEF9BEF2B, +0xC37EDA3F3FFC3FE5, 0x1CAAC75555495592, 0x1059DBA2A2B2A279, 0x65C9E9EAEA8FEA03, +0xECCA6A656589650F, 0x686903BABAD2BAB9, 0x935E4A2F2FBC2F65, 0xE79D8EC0C027C04E, +0x81A160DEDE5FDEBE, 0x6C38FC1C1C701CE0, 0x2EE746FDFDD3FDBB, 0x649A1F4D4D294D52, +0xE0397692927292E4, 0xBCEAFA7575C9758F, 0x1E0C360606180630, 0x9809AE8A8A128A24, +0x40794BB2B2F2B2F9, 0x59D185E6E6BFE663, 0x361C7E0E0E380E70, 0x633EE71F1F7C1FF8, +0xF7C4556262956237, 0xA3B53AD4D477D4EE, 0x324D81A8A89AA829, 0xF4315296966296C4, +0x3AEF62F9F9C3F99B, 0xF697A3C5C533C566, 0xB14A102525942535, 0x20B2AB59597959F2, +0xAE15D084842A8454, 0xA7E4C57272D572B7, 0xDD72EC3939E439D5, 0x6198164C4C2D4C5A, +0x3BBC945E5E655ECA, 0x85F09F7878FD78E7, 0xD870E53838E038DD, 0x8605988C8C0A8C14, +0xB2BF17D1D163D1C6, 0x0B57E4A5A5AEA541, 0x4DD9A1E2E2AFE243, 0xF8C24E616199612F, +0x457B42B3B3F6B3F1, 0xA542342121842115, 0xD625089C9C4A9C94, 0x663CEE1E1E781EF0, +0x5286614343114322, 0xFC93B1C7C73BC776, 0x2BE54FFCFCD7FCB3, 0x1408240404100420, +0x08A2E351515951B2, 0xC72F2599995E99BC, 0xC4DA226D6DA96D4F, 0x391A650D0D340D68, +0x35E979FAFACFFA83, 0x84A369DFDF5BDFB6, 0x9BFCA97E7EE57ED7, 0xB44819242490243D, +0xD776FE3B3BEC3BC5, 0x3D4B9AABAB96AB31, 0xD181F0CECE1FCE3E, 0x5522991111441188, +0x8903838F8F068F0C, 0x6B9C044E4E254E4A, 0x517366B7B7E6B7D1, 0x60CBE0EBEB8BEB0B, +0xCC78C13C3CF03CFD, 0xBF1FFD81813E817C, 0xFE354094946A94D4, 0x0CF31CF7F7FBF7EB, +0x676F18B9B9DEB9A1, 0x5F268B13134C1398, 0x9C58512C2CB02C7D, 0xB8BB05D3D36BD3D6, +0x5CD38CE7E7BBE76B, 0xCBDC396E6EA56E57, 0xF395AAC4C437C46E, 0x0F061B03030C0318, +0x13ACDC565645568A, 0x49885E44440D441A, 0x9EFEA07F7FE17FDF, 0x374F88A9A99EA921, +0x8254672A2AA82A4D, 0x6D6B0ABBBBD6BBB1, 0xE29F87C1C123C146, 0x02A6F153535153A2, +0x8BA572DCDC57DCAE, 0x2716530B0B2C0B58, 0xD327019D9D4E9D9C, 0xC1D82B6C6CAD6C47, +0xF562A43131C43195, 0xB9E8F37474CD7487, 0x09F115F6F6FFF6E3, 0x438C4C464605460A, +0x2645A5ACAC8AAC09, 0x970FB589891E893C, 0x4428B414145014A0, 0x42DFBAE1E1A3E15B, +0x4E2CA616165816B0, 0xD274F73A3AE83ACD, 0xD0D2066969B9696F, 0x2D12410909240948, +0xADE0D77070DD70A7, 0x54716FB6B6E2B6D9, 0xB7BD1ED0D067D0CE, 0x7EC7D6EDED93ED3B, +0xDB85E2CCCC17CC2E, 0x578468424215422A, 0xC22D2C98985A98B4, 0x0E55EDA4A4AAA449, +0x8850752828A0285D, 0x31B8865C5C6D5CDA, 0x3FED6BF8F8C7F893, 0xA411C28686228644 }; + +const u64bit Whirlpool::C4[256] = { +0xC07830D818186018, 0x05AF462623238C23, 0x7EF991B8C6C63FC6, 0x136FCDFBE8E887E8, +0x4CA113CB87872687, 0xA9626D11B8B8DAB8, 0x0805020901010401, 0x426E9E0D4F4F214F, +0xADEE6C9B3636D836, 0x590451FFA6A6A2A6, 0xDEBDB90CD2D26FD2, 0xFB06F70EF5F5F3F5, +0xEF80F2967979F979, 0x5FCEDE306F6FA16F, 0xFCEF3F6D91917E91, 0xAA07A4F852525552, +0x27FDC04760609D60, 0x89766535BCBCCABC, 0xACCD2B379B9B569B, 0x048C018A8E8E028E, +0x71155BD2A3A3B6A3, 0x603C186C0C0C300C, 0xFF8AF6847B7BF17B, 0xB5E16A803535D435, +0xE8693AF51D1D741D, 0x5347DDB3E0E0A7E0, 0xF6ACB321D7D77BD7, 0x5EED999CC2C22FC2, +0x6D965C432E2EB82E, 0x627A96294B4B314B, 0xA321E15DFEFEDFFE, 0x8216AED557574157, +0xA8412ABD15155415, 0x9FB6EEE87777C177, 0xA5EB6E923737DC37, 0x7B56D79EE5E5B3E5, +0x8CD923139F9F469F, 0xD317FD23F0F0E7F0, 0x6A7F94204A4A354A, 0x9E95A944DADA4FDA, +0xFA25B0A258587D58, 0x06CA8FCFC9C903C9, 0x558D527C2929A429, 0x5022145A0A0A280A, +0xE14F7F50B1B1FEB1, 0x691A5DC9A0A0BAA0, 0x7FDAD6146B6BB16B, 0x5CAB17D985852E85, +0x8173673CBDBDCEBD, 0xD234BA8F5D5D695D, 0x8050209010104010, 0xF303F507F4F4F7F4, +0x16C08BDDCBCB0BCB, 0xEDC67CD33E3EF83E, 0x28110A2D05051405, 0x1FE6CE7867678167, +0x7353D597E4E4B7E4, 0x25BB4E0227279C27, 0x3258827341411941, 0x2C9D0BA78B8B168B, +0x510153F6A7A7A6A7, 0xCF94FAB27D7DE97D, 0xDCFB374995956E95, 0x8E9FAD56D8D847D8, +0x8B30EB70FBFBCBFB, 0x2371C1CDEEEE9FEE, 0xC791F8BB7C7CED7C, 0x17E3CC7166668566, +0xA68EA77BDDDD53DD, 0xB84B2EAF17175C17, 0x02468E4547470147, 0x84DC211A9E9E429E, +0x1EC589D4CACA0FCA, 0x75995A582D2DB42D, 0x9179632EBFBFC6BF, 0x381B0E3F07071C07, +0x012347ACADAD8EAD, 0xEA2FB4B05A5A755A, 0x6CB51BEF83833683, 0x85FF66B63333CC33, +0x3FF2C65C63639163, 0x100A041202020802, 0x39384993AAAA92AA, 0xAFA8E2DE7171D971, +0x0ECF8DC6C8C807C8, 0xC87D32D119196419, 0x7270923B49493949, 0x869AAF5FD9D943D9, +0xC31DF931F2F2EFF2, 0x4B48DBA8E3E3ABE3, 0xE22AB6B95B5B715B, 0x34920DBC88881A88, +0xA4C8293E9A9A529A, 0x2DBE4C0B26269826, 0x8DFA64BF3232C832, 0xE94A7D59B0B0FAB0, +0x1B6ACFF2E9E983E9, 0x78331E770F0F3C0F, 0xE6A6B733D5D573D5, 0x74BA1DF480803A80, +0x997C6127BEBEC2BE, 0x26DE87EBCDCD13CD, 0xBDE468893434D034, 0x7A75903248483D48, +0xAB24E354FFFFDBFF, 0xF78FF48D7A7AF57A, 0xF4EA3D6490907A90, 0xC23EBE9D5F5F615F, +0x1DA0403D20208020, 0x67D5D00F6868BD68, 0xD07234CA1A1A681A, 0x192C41B7AEAE82AE, +0xC95E757DB4B4EAB4, 0x9A19A8CE54544D54, 0xECE53B7F93937693, 0x0DAA442F22228822, +0x07E9C86364648D64, 0xDB12FF2AF1F1E3F1, 0xBFA2E6CC7373D173, 0x905A248212124812, +0x3A5D807A40401D40, 0x4028104808082008, 0x56E89B95C3C32BC3, 0x337BC5DFECEC97EC, +0x9690AB4DDBDB4BDB, 0x611F5FC0A1A1BEA1, 0x1C8307918D8D0E8D, 0xF5C97AC83D3DF43D, +0xCCF1335B97976697, 0x0000000000000000, 0x36D483F9CFCF1BCF, 0x4587566E2B2BAC2B, +0x97B3ECE17676C576, 0x64B019E682823282, 0xFEA9B128D6D67FD6, 0xD87736C31B1B6C1B, +0xC15B7774B5B5EEB5, 0x112943BEAFAF86AF, 0x77DFD41D6A6AB56A, 0xBA0DA0EA50505D50, +0x124C8A5745450945, 0xCB18FB38F3F3EBF3, 0x9DF060AD3030C030, 0x2B74C3C4EFEF9BEF, +0xE5C37EDA3F3FFC3F, 0x921CAAC755554955, 0x791059DBA2A2B2A2, 0x0365C9E9EAEA8FEA, +0x0FECCA6A65658965, 0xB9686903BABAD2BA, 0x65935E4A2F2FBC2F, 0x4EE79D8EC0C027C0, +0xBE81A160DEDE5FDE, 0xE06C38FC1C1C701C, 0xBB2EE746FDFDD3FD, 0x52649A1F4D4D294D, +0xE4E0397692927292, 0x8FBCEAFA7575C975, 0x301E0C3606061806, 0x249809AE8A8A128A, +0xF940794BB2B2F2B2, 0x6359D185E6E6BFE6, 0x70361C7E0E0E380E, 0xF8633EE71F1F7C1F, +0x37F7C45562629562, 0xEEA3B53AD4D477D4, 0x29324D81A8A89AA8, 0xC4F4315296966296, +0x9B3AEF62F9F9C3F9, 0x66F697A3C5C533C5, 0x35B14A1025259425, 0xF220B2AB59597959, +0x54AE15D084842A84, 0xB7A7E4C57272D572, 0xD5DD72EC3939E439, 0x5A6198164C4C2D4C, +0xCA3BBC945E5E655E, 0xE785F09F7878FD78, 0xDDD870E53838E038, 0x148605988C8C0A8C, +0xC6B2BF17D1D163D1, 0x410B57E4A5A5AEA5, 0x434DD9A1E2E2AFE2, 0x2FF8C24E61619961, +0xF1457B42B3B3F6B3, 0x15A5423421218421, 0x94D625089C9C4A9C, 0xF0663CEE1E1E781E, +0x2252866143431143, 0x76FC93B1C7C73BC7, 0xB32BE54FFCFCD7FC, 0x2014082404041004, +0xB208A2E351515951, 0xBCC72F2599995E99, 0x4FC4DA226D6DA96D, 0x68391A650D0D340D, +0x8335E979FAFACFFA, 0xB684A369DFDF5BDF, 0xD79BFCA97E7EE57E, 0x3DB4481924249024, +0xC5D776FE3B3BEC3B, 0x313D4B9AABAB96AB, 0x3ED181F0CECE1FCE, 0x8855229911114411, +0x0C8903838F8F068F, 0x4A6B9C044E4E254E, 0xD1517366B7B7E6B7, 0x0B60CBE0EBEB8BEB, +0xFDCC78C13C3CF03C, 0x7CBF1FFD81813E81, 0xD4FE354094946A94, 0xEB0CF31CF7F7FBF7, +0xA1676F18B9B9DEB9, 0x985F268B13134C13, 0x7D9C58512C2CB02C, 0xD6B8BB05D3D36BD3, +0x6B5CD38CE7E7BBE7, 0x57CBDC396E6EA56E, 0x6EF395AAC4C437C4, 0x180F061B03030C03, +0x8A13ACDC56564556, 0x1A49885E44440D44, 0xDF9EFEA07F7FE17F, 0x21374F88A9A99EA9, +0x4D8254672A2AA82A, 0xB16D6B0ABBBBD6BB, 0x46E29F87C1C123C1, 0xA202A6F153535153, +0xAE8BA572DCDC57DC, 0x582716530B0B2C0B, 0x9CD327019D9D4E9D, 0x47C1D82B6C6CAD6C, +0x95F562A43131C431, 0x87B9E8F37474CD74, 0xE309F115F6F6FFF6, 0x0A438C4C46460546, +0x092645A5ACAC8AAC, 0x3C970FB589891E89, 0xA04428B414145014, 0x5B42DFBAE1E1A3E1, +0xB04E2CA616165816, 0xCDD274F73A3AE83A, 0x6FD0D2066969B969, 0x482D124109092409, +0xA7ADE0D77070DD70, 0xD954716FB6B6E2B6, 0xCEB7BD1ED0D067D0, 0x3B7EC7D6EDED93ED, +0x2EDB85E2CCCC17CC, 0x2A57846842421542, 0xB4C22D2C98985A98, 0x490E55EDA4A4AAA4, +0x5D8850752828A028, 0xDA31B8865C5C6D5C, 0x933FED6BF8F8C7F8, 0x44A411C286862286 }; + +const u64bit Whirlpool::C5[256] = { +0x18C07830D8181860, 0x2305AF462623238C, 0xC67EF991B8C6C63F, 0xE8136FCDFBE8E887, +0x874CA113CB878726, 0xB8A9626D11B8B8DA, 0x0108050209010104, 0x4F426E9E0D4F4F21, +0x36ADEE6C9B3636D8, 0xA6590451FFA6A6A2, 0xD2DEBDB90CD2D26F, 0xF5FB06F70EF5F5F3, +0x79EF80F2967979F9, 0x6F5FCEDE306F6FA1, 0x91FCEF3F6D91917E, 0x52AA07A4F8525255, +0x6027FDC04760609D, 0xBC89766535BCBCCA, 0x9BACCD2B379B9B56, 0x8E048C018A8E8E02, +0xA371155BD2A3A3B6, 0x0C603C186C0C0C30, 0x7BFF8AF6847B7BF1, 0x35B5E16A803535D4, +0x1DE8693AF51D1D74, 0xE05347DDB3E0E0A7, 0xD7F6ACB321D7D77B, 0xC25EED999CC2C22F, +0x2E6D965C432E2EB8, 0x4B627A96294B4B31, 0xFEA321E15DFEFEDF, 0x578216AED5575741, +0x15A8412ABD151554, 0x779FB6EEE87777C1, 0x37A5EB6E923737DC, 0xE57B56D79EE5E5B3, +0x9F8CD923139F9F46, 0xF0D317FD23F0F0E7, 0x4A6A7F94204A4A35, 0xDA9E95A944DADA4F, +0x58FA25B0A258587D, 0xC906CA8FCFC9C903, 0x29558D527C2929A4, 0x0A5022145A0A0A28, +0xB1E14F7F50B1B1FE, 0xA0691A5DC9A0A0BA, 0x6B7FDAD6146B6BB1, 0x855CAB17D985852E, +0xBD8173673CBDBDCE, 0x5DD234BA8F5D5D69, 0x1080502090101040, 0xF4F303F507F4F4F7, +0xCB16C08BDDCBCB0B, 0x3EEDC67CD33E3EF8, 0x0528110A2D050514, 0x671FE6CE78676781, +0xE47353D597E4E4B7, 0x2725BB4E0227279C, 0x4132588273414119, 0x8B2C9D0BA78B8B16, +0xA7510153F6A7A7A6, 0x7DCF94FAB27D7DE9, 0x95DCFB374995956E, 0xD88E9FAD56D8D847, +0xFB8B30EB70FBFBCB, 0xEE2371C1CDEEEE9F, 0x7CC791F8BB7C7CED, 0x6617E3CC71666685, +0xDDA68EA77BDDDD53, 0x17B84B2EAF17175C, 0x4702468E45474701, 0x9E84DC211A9E9E42, +0xCA1EC589D4CACA0F, 0x2D75995A582D2DB4, 0xBF9179632EBFBFC6, 0x07381B0E3F07071C, +0xAD012347ACADAD8E, 0x5AEA2FB4B05A5A75, 0x836CB51BEF838336, 0x3385FF66B63333CC, +0x633FF2C65C636391, 0x02100A0412020208, 0xAA39384993AAAA92, 0x71AFA8E2DE7171D9, +0xC80ECF8DC6C8C807, 0x19C87D32D1191964, 0x497270923B494939, 0xD9869AAF5FD9D943, +0xF2C31DF931F2F2EF, 0xE34B48DBA8E3E3AB, 0x5BE22AB6B95B5B71, 0x8834920DBC88881A, +0x9AA4C8293E9A9A52, 0x262DBE4C0B262698, 0x328DFA64BF3232C8, 0xB0E94A7D59B0B0FA, +0xE91B6ACFF2E9E983, 0x0F78331E770F0F3C, 0xD5E6A6B733D5D573, 0x8074BA1DF480803A, +0xBE997C6127BEBEC2, 0xCD26DE87EBCDCD13, 0x34BDE468893434D0, 0x487A75903248483D, +0xFFAB24E354FFFFDB, 0x7AF78FF48D7A7AF5, 0x90F4EA3D6490907A, 0x5FC23EBE9D5F5F61, +0x201DA0403D202080, 0x6867D5D00F6868BD, 0x1AD07234CA1A1A68, 0xAE192C41B7AEAE82, +0xB4C95E757DB4B4EA, 0x549A19A8CE54544D, 0x93ECE53B7F939376, 0x220DAA442F222288, +0x6407E9C86364648D, 0xF1DB12FF2AF1F1E3, 0x73BFA2E6CC7373D1, 0x12905A2482121248, +0x403A5D807A40401D, 0x0840281048080820, 0xC356E89B95C3C32B, 0xEC337BC5DFECEC97, +0xDB9690AB4DDBDB4B, 0xA1611F5FC0A1A1BE, 0x8D1C8307918D8D0E, 0x3DF5C97AC83D3DF4, +0x97CCF1335B979766, 0x0000000000000000, 0xCF36D483F9CFCF1B, 0x2B4587566E2B2BAC, +0x7697B3ECE17676C5, 0x8264B019E6828232, 0xD6FEA9B128D6D67F, 0x1BD87736C31B1B6C, +0xB5C15B7774B5B5EE, 0xAF112943BEAFAF86, 0x6A77DFD41D6A6AB5, 0x50BA0DA0EA50505D, +0x45124C8A57454509, 0xF3CB18FB38F3F3EB, 0x309DF060AD3030C0, 0xEF2B74C3C4EFEF9B, +0x3FE5C37EDA3F3FFC, 0x55921CAAC7555549, 0xA2791059DBA2A2B2, 0xEA0365C9E9EAEA8F, +0x650FECCA6A656589, 0xBAB9686903BABAD2, 0x2F65935E4A2F2FBC, 0xC04EE79D8EC0C027, +0xDEBE81A160DEDE5F, 0x1CE06C38FC1C1C70, 0xFDBB2EE746FDFDD3, 0x4D52649A1F4D4D29, +0x92E4E03976929272, 0x758FBCEAFA7575C9, 0x06301E0C36060618, 0x8A249809AE8A8A12, +0xB2F940794BB2B2F2, 0xE66359D185E6E6BF, 0x0E70361C7E0E0E38, 0x1FF8633EE71F1F7C, +0x6237F7C455626295, 0xD4EEA3B53AD4D477, 0xA829324D81A8A89A, 0x96C4F43152969662, +0xF99B3AEF62F9F9C3, 0xC566F697A3C5C533, 0x2535B14A10252594, 0x59F220B2AB595979, +0x8454AE15D084842A, 0x72B7A7E4C57272D5, 0x39D5DD72EC3939E4, 0x4C5A6198164C4C2D, +0x5ECA3BBC945E5E65, 0x78E785F09F7878FD, 0x38DDD870E53838E0, 0x8C148605988C8C0A, +0xD1C6B2BF17D1D163, 0xA5410B57E4A5A5AE, 0xE2434DD9A1E2E2AF, 0x612FF8C24E616199, +0xB3F1457B42B3B3F6, 0x2115A54234212184, 0x9C94D625089C9C4A, 0x1EF0663CEE1E1E78, +0x4322528661434311, 0xC776FC93B1C7C73B, 0xFCB32BE54FFCFCD7, 0x0420140824040410, +0x51B208A2E3515159, 0x99BCC72F2599995E, 0x6D4FC4DA226D6DA9, 0x0D68391A650D0D34, +0xFA8335E979FAFACF, 0xDFB684A369DFDF5B, 0x7ED79BFCA97E7EE5, 0x243DB44819242490, +0x3BC5D776FE3B3BEC, 0xAB313D4B9AABAB96, 0xCE3ED181F0CECE1F, 0x1188552299111144, +0x8F0C8903838F8F06, 0x4E4A6B9C044E4E25, 0xB7D1517366B7B7E6, 0xEB0B60CBE0EBEB8B, +0x3CFDCC78C13C3CF0, 0x817CBF1FFD81813E, 0x94D4FE354094946A, 0xF7EB0CF31CF7F7FB, +0xB9A1676F18B9B9DE, 0x13985F268B13134C, 0x2C7D9C58512C2CB0, 0xD3D6B8BB05D3D36B, +0xE76B5CD38CE7E7BB, 0x6E57CBDC396E6EA5, 0xC46EF395AAC4C437, 0x03180F061B03030C, +0x568A13ACDC565645, 0x441A49885E44440D, 0x7FDF9EFEA07F7FE1, 0xA921374F88A9A99E, +0x2A4D8254672A2AA8, 0xBBB16D6B0ABBBBD6, 0xC146E29F87C1C123, 0x53A202A6F1535351, +0xDCAE8BA572DCDC57, 0x0B582716530B0B2C, 0x9D9CD327019D9D4E, 0x6C47C1D82B6C6CAD, +0x3195F562A43131C4, 0x7487B9E8F37474CD, 0xF6E309F115F6F6FF, 0x460A438C4C464605, +0xAC092645A5ACAC8A, 0x893C970FB589891E, 0x14A04428B4141450, 0xE15B42DFBAE1E1A3, +0x16B04E2CA6161658, 0x3ACDD274F73A3AE8, 0x696FD0D2066969B9, 0x09482D1241090924, +0x70A7ADE0D77070DD, 0xB6D954716FB6B6E2, 0xD0CEB7BD1ED0D067, 0xED3B7EC7D6EDED93, +0xCC2EDB85E2CCCC17, 0x422A578468424215, 0x98B4C22D2C98985A, 0xA4490E55EDA4A4AA, +0x285D8850752828A0, 0x5CDA31B8865C5C6D, 0xF8933FED6BF8F8C7, 0x8644A411C2868622 }; + +const u64bit Whirlpool::C6[256] = { +0x6018C07830D81818, 0x8C2305AF46262323, 0x3FC67EF991B8C6C6, 0x87E8136FCDFBE8E8, +0x26874CA113CB8787, 0xDAB8A9626D11B8B8, 0x0401080502090101, 0x214F426E9E0D4F4F, +0xD836ADEE6C9B3636, 0xA2A6590451FFA6A6, 0x6FD2DEBDB90CD2D2, 0xF3F5FB06F70EF5F5, +0xF979EF80F2967979, 0xA16F5FCEDE306F6F, 0x7E91FCEF3F6D9191, 0x5552AA07A4F85252, +0x9D6027FDC0476060, 0xCABC89766535BCBC, 0x569BACCD2B379B9B, 0x028E048C018A8E8E, +0xB6A371155BD2A3A3, 0x300C603C186C0C0C, 0xF17BFF8AF6847B7B, 0xD435B5E16A803535, +0x741DE8693AF51D1D, 0xA7E05347DDB3E0E0, 0x7BD7F6ACB321D7D7, 0x2FC25EED999CC2C2, +0xB82E6D965C432E2E, 0x314B627A96294B4B, 0xDFFEA321E15DFEFE, 0x41578216AED55757, +0x5415A8412ABD1515, 0xC1779FB6EEE87777, 0xDC37A5EB6E923737, 0xB3E57B56D79EE5E5, +0x469F8CD923139F9F, 0xE7F0D317FD23F0F0, 0x354A6A7F94204A4A, 0x4FDA9E95A944DADA, +0x7D58FA25B0A25858, 0x03C906CA8FCFC9C9, 0xA429558D527C2929, 0x280A5022145A0A0A, +0xFEB1E14F7F50B1B1, 0xBAA0691A5DC9A0A0, 0xB16B7FDAD6146B6B, 0x2E855CAB17D98585, +0xCEBD8173673CBDBD, 0x695DD234BA8F5D5D, 0x4010805020901010, 0xF7F4F303F507F4F4, +0x0BCB16C08BDDCBCB, 0xF83EEDC67CD33E3E, 0x140528110A2D0505, 0x81671FE6CE786767, +0xB7E47353D597E4E4, 0x9C2725BB4E022727, 0x1941325882734141, 0x168B2C9D0BA78B8B, +0xA6A7510153F6A7A7, 0xE97DCF94FAB27D7D, 0x6E95DCFB37499595, 0x47D88E9FAD56D8D8, +0xCBFB8B30EB70FBFB, 0x9FEE2371C1CDEEEE, 0xED7CC791F8BB7C7C, 0x856617E3CC716666, +0x53DDA68EA77BDDDD, 0x5C17B84B2EAF1717, 0x014702468E454747, 0x429E84DC211A9E9E, +0x0FCA1EC589D4CACA, 0xB42D75995A582D2D, 0xC6BF9179632EBFBF, 0x1C07381B0E3F0707, +0x8EAD012347ACADAD, 0x755AEA2FB4B05A5A, 0x36836CB51BEF8383, 0xCC3385FF66B63333, +0x91633FF2C65C6363, 0x0802100A04120202, 0x92AA39384993AAAA, 0xD971AFA8E2DE7171, +0x07C80ECF8DC6C8C8, 0x6419C87D32D11919, 0x39497270923B4949, 0x43D9869AAF5FD9D9, +0xEFF2C31DF931F2F2, 0xABE34B48DBA8E3E3, 0x715BE22AB6B95B5B, 0x1A8834920DBC8888, +0x529AA4C8293E9A9A, 0x98262DBE4C0B2626, 0xC8328DFA64BF3232, 0xFAB0E94A7D59B0B0, +0x83E91B6ACFF2E9E9, 0x3C0F78331E770F0F, 0x73D5E6A6B733D5D5, 0x3A8074BA1DF48080, +0xC2BE997C6127BEBE, 0x13CD26DE87EBCDCD, 0xD034BDE468893434, 0x3D487A7590324848, +0xDBFFAB24E354FFFF, 0xF57AF78FF48D7A7A, 0x7A90F4EA3D649090, 0x615FC23EBE9D5F5F, +0x80201DA0403D2020, 0xBD6867D5D00F6868, 0x681AD07234CA1A1A, 0x82AE192C41B7AEAE, +0xEAB4C95E757DB4B4, 0x4D549A19A8CE5454, 0x7693ECE53B7F9393, 0x88220DAA442F2222, +0x8D6407E9C8636464, 0xE3F1DB12FF2AF1F1, 0xD173BFA2E6CC7373, 0x4812905A24821212, +0x1D403A5D807A4040, 0x2008402810480808, 0x2BC356E89B95C3C3, 0x97EC337BC5DFECEC, +0x4BDB9690AB4DDBDB, 0xBEA1611F5FC0A1A1, 0x0E8D1C8307918D8D, 0xF43DF5C97AC83D3D, +0x6697CCF1335B9797, 0x0000000000000000, 0x1BCF36D483F9CFCF, 0xAC2B4587566E2B2B, +0xC57697B3ECE17676, 0x328264B019E68282, 0x7FD6FEA9B128D6D6, 0x6C1BD87736C31B1B, +0xEEB5C15B7774B5B5, 0x86AF112943BEAFAF, 0xB56A77DFD41D6A6A, 0x5D50BA0DA0EA5050, +0x0945124C8A574545, 0xEBF3CB18FB38F3F3, 0xC0309DF060AD3030, 0x9BEF2B74C3C4EFEF, +0xFC3FE5C37EDA3F3F, 0x4955921CAAC75555, 0xB2A2791059DBA2A2, 0x8FEA0365C9E9EAEA, +0x89650FECCA6A6565, 0xD2BAB9686903BABA, 0xBC2F65935E4A2F2F, 0x27C04EE79D8EC0C0, +0x5FDEBE81A160DEDE, 0x701CE06C38FC1C1C, 0xD3FDBB2EE746FDFD, 0x294D52649A1F4D4D, +0x7292E4E039769292, 0xC9758FBCEAFA7575, 0x1806301E0C360606, 0x128A249809AE8A8A, +0xF2B2F940794BB2B2, 0xBFE66359D185E6E6, 0x380E70361C7E0E0E, 0x7C1FF8633EE71F1F, +0x956237F7C4556262, 0x77D4EEA3B53AD4D4, 0x9AA829324D81A8A8, 0x6296C4F431529696, +0xC3F99B3AEF62F9F9, 0x33C566F697A3C5C5, 0x942535B14A102525, 0x7959F220B2AB5959, +0x2A8454AE15D08484, 0xD572B7A7E4C57272, 0xE439D5DD72EC3939, 0x2D4C5A6198164C4C, +0x655ECA3BBC945E5E, 0xFD78E785F09F7878, 0xE038DDD870E53838, 0x0A8C148605988C8C, +0x63D1C6B2BF17D1D1, 0xAEA5410B57E4A5A5, 0xAFE2434DD9A1E2E2, 0x99612FF8C24E6161, +0xF6B3F1457B42B3B3, 0x842115A542342121, 0x4A9C94D625089C9C, 0x781EF0663CEE1E1E, +0x1143225286614343, 0x3BC776FC93B1C7C7, 0xD7FCB32BE54FFCFC, 0x1004201408240404, +0x5951B208A2E35151, 0x5E99BCC72F259999, 0xA96D4FC4DA226D6D, 0x340D68391A650D0D, +0xCFFA8335E979FAFA, 0x5BDFB684A369DFDF, 0xE57ED79BFCA97E7E, 0x90243DB448192424, +0xEC3BC5D776FE3B3B, 0x96AB313D4B9AABAB, 0x1FCE3ED181F0CECE, 0x4411885522991111, +0x068F0C8903838F8F, 0x254E4A6B9C044E4E, 0xE6B7D1517366B7B7, 0x8BEB0B60CBE0EBEB, +0xF03CFDCC78C13C3C, 0x3E817CBF1FFD8181, 0x6A94D4FE35409494, 0xFBF7EB0CF31CF7F7, +0xDEB9A1676F18B9B9, 0x4C13985F268B1313, 0xB02C7D9C58512C2C, 0x6BD3D6B8BB05D3D3, +0xBBE76B5CD38CE7E7, 0xA56E57CBDC396E6E, 0x37C46EF395AAC4C4, 0x0C03180F061B0303, +0x45568A13ACDC5656, 0x0D441A49885E4444, 0xE17FDF9EFEA07F7F, 0x9EA921374F88A9A9, +0xA82A4D8254672A2A, 0xD6BBB16D6B0ABBBB, 0x23C146E29F87C1C1, 0x5153A202A6F15353, +0x57DCAE8BA572DCDC, 0x2C0B582716530B0B, 0x4E9D9CD327019D9D, 0xAD6C47C1D82B6C6C, +0xC43195F562A43131, 0xCD7487B9E8F37474, 0xFFF6E309F115F6F6, 0x05460A438C4C4646, +0x8AAC092645A5ACAC, 0x1E893C970FB58989, 0x5014A04428B41414, 0xA3E15B42DFBAE1E1, +0x5816B04E2CA61616, 0xE83ACDD274F73A3A, 0xB9696FD0D2066969, 0x2409482D12410909, +0xDD70A7ADE0D77070, 0xE2B6D954716FB6B6, 0x67D0CEB7BD1ED0D0, 0x93ED3B7EC7D6EDED, +0x17CC2EDB85E2CCCC, 0x15422A5784684242, 0x5A98B4C22D2C9898, 0xAAA4490E55EDA4A4, +0xA0285D8850752828, 0x6D5CDA31B8865C5C, 0xC7F8933FED6BF8F8, 0x228644A411C28686 }; + +const u64bit Whirlpool::C7[256] = { +0x186018C07830D818, 0x238C2305AF462623, 0xC63FC67EF991B8C6, 0xE887E8136FCDFBE8, +0x8726874CA113CB87, 0xB8DAB8A9626D11B8, 0x0104010805020901, 0x4F214F426E9E0D4F, +0x36D836ADEE6C9B36, 0xA6A2A6590451FFA6, 0xD26FD2DEBDB90CD2, 0xF5F3F5FB06F70EF5, +0x79F979EF80F29679, 0x6FA16F5FCEDE306F, 0x917E91FCEF3F6D91, 0x525552AA07A4F852, +0x609D6027FDC04760, 0xBCCABC89766535BC, 0x9B569BACCD2B379B, 0x8E028E048C018A8E, +0xA3B6A371155BD2A3, 0x0C300C603C186C0C, 0x7BF17BFF8AF6847B, 0x35D435B5E16A8035, +0x1D741DE8693AF51D, 0xE0A7E05347DDB3E0, 0xD77BD7F6ACB321D7, 0xC22FC25EED999CC2, +0x2EB82E6D965C432E, 0x4B314B627A96294B, 0xFEDFFEA321E15DFE, 0x5741578216AED557, +0x155415A8412ABD15, 0x77C1779FB6EEE877, 0x37DC37A5EB6E9237, 0xE5B3E57B56D79EE5, +0x9F469F8CD923139F, 0xF0E7F0D317FD23F0, 0x4A354A6A7F94204A, 0xDA4FDA9E95A944DA, +0x587D58FA25B0A258, 0xC903C906CA8FCFC9, 0x29A429558D527C29, 0x0A280A5022145A0A, +0xB1FEB1E14F7F50B1, 0xA0BAA0691A5DC9A0, 0x6BB16B7FDAD6146B, 0x852E855CAB17D985, +0xBDCEBD8173673CBD, 0x5D695DD234BA8F5D, 0x1040108050209010, 0xF4F7F4F303F507F4, +0xCB0BCB16C08BDDCB, 0x3EF83EEDC67CD33E, 0x05140528110A2D05, 0x6781671FE6CE7867, +0xE4B7E47353D597E4, 0x279C2725BB4E0227, 0x4119413258827341, 0x8B168B2C9D0BA78B, +0xA7A6A7510153F6A7, 0x7DE97DCF94FAB27D, 0x956E95DCFB374995, 0xD847D88E9FAD56D8, +0xFBCBFB8B30EB70FB, 0xEE9FEE2371C1CDEE, 0x7CED7CC791F8BB7C, 0x66856617E3CC7166, +0xDD53DDA68EA77BDD, 0x175C17B84B2EAF17, 0x47014702468E4547, 0x9E429E84DC211A9E, +0xCA0FCA1EC589D4CA, 0x2DB42D75995A582D, 0xBFC6BF9179632EBF, 0x071C07381B0E3F07, +0xAD8EAD012347ACAD, 0x5A755AEA2FB4B05A, 0x8336836CB51BEF83, 0x33CC3385FF66B633, +0x6391633FF2C65C63, 0x020802100A041202, 0xAA92AA39384993AA, 0x71D971AFA8E2DE71, +0xC807C80ECF8DC6C8, 0x196419C87D32D119, 0x4939497270923B49, 0xD943D9869AAF5FD9, +0xF2EFF2C31DF931F2, 0xE3ABE34B48DBA8E3, 0x5B715BE22AB6B95B, 0x881A8834920DBC88, +0x9A529AA4C8293E9A, 0x2698262DBE4C0B26, 0x32C8328DFA64BF32, 0xB0FAB0E94A7D59B0, +0xE983E91B6ACFF2E9, 0x0F3C0F78331E770F, 0xD573D5E6A6B733D5, 0x803A8074BA1DF480, +0xBEC2BE997C6127BE, 0xCD13CD26DE87EBCD, 0x34D034BDE4688934, 0x483D487A75903248, +0xFFDBFFAB24E354FF, 0x7AF57AF78FF48D7A, 0x907A90F4EA3D6490, 0x5F615FC23EBE9D5F, +0x2080201DA0403D20, 0x68BD6867D5D00F68, 0x1A681AD07234CA1A, 0xAE82AE192C41B7AE, +0xB4EAB4C95E757DB4, 0x544D549A19A8CE54, 0x937693ECE53B7F93, 0x2288220DAA442F22, +0x648D6407E9C86364, 0xF1E3F1DB12FF2AF1, 0x73D173BFA2E6CC73, 0x124812905A248212, +0x401D403A5D807A40, 0x0820084028104808, 0xC32BC356E89B95C3, 0xEC97EC337BC5DFEC, +0xDB4BDB9690AB4DDB, 0xA1BEA1611F5FC0A1, 0x8D0E8D1C8307918D, 0x3DF43DF5C97AC83D, +0x976697CCF1335B97, 0x0000000000000000, 0xCF1BCF36D483F9CF, 0x2BAC2B4587566E2B, +0x76C57697B3ECE176, 0x82328264B019E682, 0xD67FD6FEA9B128D6, 0x1B6C1BD87736C31B, +0xB5EEB5C15B7774B5, 0xAF86AF112943BEAF, 0x6AB56A77DFD41D6A, 0x505D50BA0DA0EA50, +0x450945124C8A5745, 0xF3EBF3CB18FB38F3, 0x30C0309DF060AD30, 0xEF9BEF2B74C3C4EF, +0x3FFC3FE5C37EDA3F, 0x554955921CAAC755, 0xA2B2A2791059DBA2, 0xEA8FEA0365C9E9EA, +0x6589650FECCA6A65, 0xBAD2BAB9686903BA, 0x2FBC2F65935E4A2F, 0xC027C04EE79D8EC0, +0xDE5FDEBE81A160DE, 0x1C701CE06C38FC1C, 0xFDD3FDBB2EE746FD, 0x4D294D52649A1F4D, +0x927292E4E0397692, 0x75C9758FBCEAFA75, 0x061806301E0C3606, 0x8A128A249809AE8A, +0xB2F2B2F940794BB2, 0xE6BFE66359D185E6, 0x0E380E70361C7E0E, 0x1F7C1FF8633EE71F, +0x62956237F7C45562, 0xD477D4EEA3B53AD4, 0xA89AA829324D81A8, 0x966296C4F4315296, +0xF9C3F99B3AEF62F9, 0xC533C566F697A3C5, 0x25942535B14A1025, 0x597959F220B2AB59, +0x842A8454AE15D084, 0x72D572B7A7E4C572, 0x39E439D5DD72EC39, 0x4C2D4C5A6198164C, +0x5E655ECA3BBC945E, 0x78FD78E785F09F78, 0x38E038DDD870E538, 0x8C0A8C148605988C, +0xD163D1C6B2BF17D1, 0xA5AEA5410B57E4A5, 0xE2AFE2434DD9A1E2, 0x6199612FF8C24E61, +0xB3F6B3F1457B42B3, 0x21842115A5423421, 0x9C4A9C94D625089C, 0x1E781EF0663CEE1E, +0x4311432252866143, 0xC73BC776FC93B1C7, 0xFCD7FCB32BE54FFC, 0x0410042014082404, +0x515951B208A2E351, 0x995E99BCC72F2599, 0x6DA96D4FC4DA226D, 0x0D340D68391A650D, +0xFACFFA8335E979FA, 0xDF5BDFB684A369DF, 0x7EE57ED79BFCA97E, 0x2490243DB4481924, +0x3BEC3BC5D776FE3B, 0xAB96AB313D4B9AAB, 0xCE1FCE3ED181F0CE, 0x1144118855229911, +0x8F068F0C8903838F, 0x4E254E4A6B9C044E, 0xB7E6B7D1517366B7, 0xEB8BEB0B60CBE0EB, +0x3CF03CFDCC78C13C, 0x813E817CBF1FFD81, 0x946A94D4FE354094, 0xF7FBF7EB0CF31CF7, +0xB9DEB9A1676F18B9, 0x134C13985F268B13, 0x2CB02C7D9C58512C, 0xD36BD3D6B8BB05D3, +0xE7BBE76B5CD38CE7, 0x6EA56E57CBDC396E, 0xC437C46EF395AAC4, 0x030C03180F061B03, +0x5645568A13ACDC56, 0x440D441A49885E44, 0x7FE17FDF9EFEA07F, 0xA99EA921374F88A9, +0x2AA82A4D8254672A, 0xBBD6BBB16D6B0ABB, 0xC123C146E29F87C1, 0x535153A202A6F153, +0xDC57DCAE8BA572DC, 0x0B2C0B582716530B, 0x9D4E9D9CD327019D, 0x6CAD6C47C1D82B6C, +0x31C43195F562A431, 0x74CD7487B9E8F374, 0xF6FFF6E309F115F6, 0x4605460A438C4C46, +0xAC8AAC092645A5AC, 0x891E893C970FB589, 0x145014A04428B414, 0xE1A3E15B42DFBAE1, +0x165816B04E2CA616, 0x3AE83ACDD274F73A, 0x69B9696FD0D20669, 0x092409482D124109, +0x70DD70A7ADE0D770, 0xB6E2B6D954716FB6, 0xD067D0CEB7BD1ED0, 0xED93ED3B7EC7D6ED, +0xCC17CC2EDB85E2CC, 0x4215422A57846842, 0x985A98B4C22D2C98, 0xA4AAA4490E55EDA4, +0x28A0285D88507528, 0x5C6D5CDA31B8865C, 0xF8C7F8933FED6BF8, 0x86228644A411C286 }; + +} diff --git a/src/lib/hash/whirlpool/whrlpool.cpp b/src/lib/hash/whirlpool/whrlpool.cpp new file mode 100644 index 000000000..5356252b2 --- /dev/null +++ b/src/lib/hash/whirlpool/whrlpool.cpp @@ -0,0 +1,146 @@ +/* +* Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Whirlpool Compression Function +*/ +void Whirlpool::compress_n(const byte in[], size_t blocks) + { + static const u64bit RC[10] = { + 0x1823C6E887B8014F, 0x36A6D2F5796F9152, + 0x60BC9B8EA30C7B35, 0x1DE0D7C22E4BFE57, + 0x157737E59FF04ADA, 0x58C9290AB1A06B85, + 0xBD5D10F4CB3E0567, 0xE427418BA77D95D8, + 0xFBEE7C66DD17479E, 0xCA2DBF07AD5A8333 + }; + + for(size_t i = 0; i != blocks; ++i) + { + load_be(&M[0], in, M.size()); + + u64bit K0, K1, K2, K3, K4, K5, K6, K7; + K0 = digest[0]; K1 = digest[1]; K2 = digest[2]; K3 = digest[3]; + K4 = digest[4]; K5 = digest[5]; K6 = digest[6]; K7 = digest[7]; + + u64bit B0, B1, B2, B3, B4, B5, B6, B7; + B0 = K0 ^ M[0]; B1 = K1 ^ M[1]; B2 = K2 ^ M[2]; B3 = K3 ^ M[3]; + B4 = K4 ^ M[4]; B5 = K5 ^ M[5]; B6 = K6 ^ M[6]; B7 = K7 ^ M[7]; + + for(size_t j = 0; j != 10; ++j) + { + u64bit T0, T1, T2, T3, T4, T5, T6, T7; + T0 = C0[get_byte(0, K0)] ^ C1[get_byte(1, K7)] ^ + C2[get_byte(2, K6)] ^ C3[get_byte(3, K5)] ^ + C4[get_byte(4, K4)] ^ C5[get_byte(5, K3)] ^ + C6[get_byte(6, K2)] ^ C7[get_byte(7, K1)] ^ RC[j]; + T1 = C0[get_byte(0, K1)] ^ C1[get_byte(1, K0)] ^ + C2[get_byte(2, K7)] ^ C3[get_byte(3, K6)] ^ + C4[get_byte(4, K5)] ^ C5[get_byte(5, K4)] ^ + C6[get_byte(6, K3)] ^ C7[get_byte(7, K2)]; + T2 = C0[get_byte(0, K2)] ^ C1[get_byte(1, K1)] ^ + C2[get_byte(2, K0)] ^ C3[get_byte(3, K7)] ^ + C4[get_byte(4, K6)] ^ C5[get_byte(5, K5)] ^ + C6[get_byte(6, K4)] ^ C7[get_byte(7, K3)]; + T3 = C0[get_byte(0, K3)] ^ C1[get_byte(1, K2)] ^ + C2[get_byte(2, K1)] ^ C3[get_byte(3, K0)] ^ + C4[get_byte(4, K7)] ^ C5[get_byte(5, K6)] ^ + C6[get_byte(6, K5)] ^ C7[get_byte(7, K4)]; + T4 = C0[get_byte(0, K4)] ^ C1[get_byte(1, K3)] ^ + C2[get_byte(2, K2)] ^ C3[get_byte(3, K1)] ^ + C4[get_byte(4, K0)] ^ C5[get_byte(5, K7)] ^ + C6[get_byte(6, K6)] ^ C7[get_byte(7, K5)]; + T5 = C0[get_byte(0, K5)] ^ C1[get_byte(1, K4)] ^ + C2[get_byte(2, K3)] ^ C3[get_byte(3, K2)] ^ + C4[get_byte(4, K1)] ^ C5[get_byte(5, K0)] ^ + C6[get_byte(6, K7)] ^ C7[get_byte(7, K6)]; + T6 = C0[get_byte(0, K6)] ^ C1[get_byte(1, K5)] ^ + C2[get_byte(2, K4)] ^ C3[get_byte(3, K3)] ^ + C4[get_byte(4, K2)] ^ C5[get_byte(5, K1)] ^ + C6[get_byte(6, K0)] ^ C7[get_byte(7, K7)]; + T7 = C0[get_byte(0, K7)] ^ C1[get_byte(1, K6)] ^ + C2[get_byte(2, K5)] ^ C3[get_byte(3, K4)] ^ + C4[get_byte(4, K3)] ^ C5[get_byte(5, K2)] ^ + C6[get_byte(6, K1)] ^ C7[get_byte(7, K0)]; + + K0 = T0; K1 = T1; K2 = T2; K3 = T3; + K4 = T4; K5 = T5; K6 = T6; K7 = T7; + + T0 = C0[get_byte(0, B0)] ^ C1[get_byte(1, B7)] ^ + C2[get_byte(2, B6)] ^ C3[get_byte(3, B5)] ^ + C4[get_byte(4, B4)] ^ C5[get_byte(5, B3)] ^ + C6[get_byte(6, B2)] ^ C7[get_byte(7, B1)] ^ K0; + T1 = C0[get_byte(0, B1)] ^ C1[get_byte(1, B0)] ^ + C2[get_byte(2, B7)] ^ C3[get_byte(3, B6)] ^ + C4[get_byte(4, B5)] ^ C5[get_byte(5, B4)] ^ + C6[get_byte(6, B3)] ^ C7[get_byte(7, B2)] ^ K1; + T2 = C0[get_byte(0, B2)] ^ C1[get_byte(1, B1)] ^ + C2[get_byte(2, B0)] ^ C3[get_byte(3, B7)] ^ + C4[get_byte(4, B6)] ^ C5[get_byte(5, B5)] ^ + C6[get_byte(6, B4)] ^ C7[get_byte(7, B3)] ^ K2; + T3 = C0[get_byte(0, B3)] ^ C1[get_byte(1, B2)] ^ + C2[get_byte(2, B1)] ^ C3[get_byte(3, B0)] ^ + C4[get_byte(4, B7)] ^ C5[get_byte(5, B6)] ^ + C6[get_byte(6, B5)] ^ C7[get_byte(7, B4)] ^ K3; + T4 = C0[get_byte(0, B4)] ^ C1[get_byte(1, B3)] ^ + C2[get_byte(2, B2)] ^ C3[get_byte(3, B1)] ^ + C4[get_byte(4, B0)] ^ C5[get_byte(5, B7)] ^ + C6[get_byte(6, B6)] ^ C7[get_byte(7, B5)] ^ K4; + T5 = C0[get_byte(0, B5)] ^ C1[get_byte(1, B4)] ^ + C2[get_byte(2, B3)] ^ C3[get_byte(3, B2)] ^ + C4[get_byte(4, B1)] ^ C5[get_byte(5, B0)] ^ + C6[get_byte(6, B7)] ^ C7[get_byte(7, B6)] ^ K5; + T6 = C0[get_byte(0, B6)] ^ C1[get_byte(1, B5)] ^ + C2[get_byte(2, B4)] ^ C3[get_byte(3, B3)] ^ + C4[get_byte(4, B2)] ^ C5[get_byte(5, B1)] ^ + C6[get_byte(6, B0)] ^ C7[get_byte(7, B7)] ^ K6; + T7 = C0[get_byte(0, B7)] ^ C1[get_byte(1, B6)] ^ + C2[get_byte(2, B5)] ^ C3[get_byte(3, B4)] ^ + C4[get_byte(4, B3)] ^ C5[get_byte(5, B2)] ^ + C6[get_byte(6, B1)] ^ C7[get_byte(7, B0)] ^ K7; + + B0 = T0; B1 = T1; B2 = T2; B3 = T3; + B4 = T4; B5 = T5; B6 = T6; B7 = T7; + } + + digest[0] ^= B0 ^ M[0]; + digest[1] ^= B1 ^ M[1]; + digest[2] ^= B2 ^ M[2]; + digest[3] ^= B3 ^ M[3]; + digest[4] ^= B4 ^ M[4]; + digest[5] ^= B5 ^ M[5]; + digest[6] ^= B6 ^ M[6]; + digest[7] ^= B7 ^ M[7]; + + in += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void Whirlpool::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 8) + store_be(digest[i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void Whirlpool::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + zeroise(digest); + } + +} diff --git a/src/lib/hash/whirlpool/whrlpool.h b/src/lib/hash/whirlpool/whrlpool.h new file mode 100644 index 000000000..d4ad805e1 --- /dev/null +++ b/src/lib/hash/whirlpool/whrlpool.h @@ -0,0 +1,47 @@ +/* +* Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_WHIRLPOOL_H__ +#define BOTAN_WHIRLPOOL_H__ + +#include + +namespace Botan { + +/** +* Whirlpool +*/ +class BOTAN_DLL Whirlpool : public MDx_HashFunction + { + public: + std::string name() const { return "Whirlpool"; } + size_t output_length() const { return 64; } + HashFunction* clone() const { return new Whirlpool; } + + void clear(); + + Whirlpool() : MDx_HashFunction(64, true, true, 32), M(8), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + static const u64bit C0[256]; + static const u64bit C1[256]; + static const u64bit C2[256]; + static const u64bit C3[256]; + static const u64bit C4[256]; + static const u64bit C5[256]; + static const u64bit C6[256]; + static const u64bit C7[256]; + + secure_vector M, digest; + }; + +} + +#endif diff --git a/src/lib/kdf/info.txt b/src/lib/kdf/info.txt new file mode 100644 index 000000000..e9cbdeb1a --- /dev/null +++ b/src/lib/kdf/info.txt @@ -0,0 +1,5 @@ +define KDF_BASE 20131128 + + +alloc + diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp new file mode 100644 index 000000000..84a0cdd15 --- /dev/null +++ b/src/lib/kdf/kdf.cpp @@ -0,0 +1,81 @@ +/* +* KDF Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_KDF1) + #include +#endif + +#if defined(BOTAN_HAS_KDF2) + #include +#endif + +#if defined(BOTAN_HAS_X942_PRF) + #include +#endif + +#if defined(BOTAN_HAS_SSL_V3_PRF) + #include +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) + #include +#endif + +namespace Botan { + +KDF* get_kdf(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(request.algo_name() == "Raw") + return nullptr; // No KDF + +#if defined(BOTAN_HAS_KDF1) + if(request.algo_name() == "KDF1" && request.arg_count() == 1) + return new KDF1(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_KDF2) + if(request.algo_name() == "KDF2" && request.arg_count() == 1) + return new KDF2(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_X942_PRF) + if(request.algo_name() == "X9.42-PRF" && request.arg_count() == 1) + return new X942_PRF(request.arg(0)); // OID +#endif + +#if defined(BOTAN_HAS_SSL_V3_PRF) + if(request.algo_name() == "SSL3-PRF" && request.arg_count() == 0) + return new SSL3_PRF; +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) + if(request.algo_name() == "TLS-PRF" && request.arg_count() == 0) + return new TLS_PRF; +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) + if(request.algo_name() == "TLS-PRF" && request.arg_count() == 0) + return new TLS_PRF; +#endif + +#if defined(BOTAN_HAS_TLS_V12_PRF) + if(request.algo_name() == "TLS-12-PRF" && request.arg_count() == 1) + return new TLS_12_PRF(af.make_mac("HMAC(" + request.arg(0) + ")")); +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +} diff --git a/src/lib/kdf/kdf.h b/src/lib/kdf/kdf.h new file mode 100644 index 000000000..b0f6e1dc3 --- /dev/null +++ b/src/lib/kdf/kdf.h @@ -0,0 +1,136 @@ +/* +* KDF/MGF +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KDF_BASE_H__ +#define BOTAN_KDF_BASE_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Key Derivation Function +*/ +class BOTAN_DLL KDF : public Algorithm + { + public: + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + */ + secure_vector derive_key(size_t key_len, + const secure_vector& secret, + const std::string& salt = "") const + { + return derive_key(key_len, &secret[0], secret.size(), + reinterpret_cast(salt.data()), + salt.length()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + */ + template + secure_vector derive_key(size_t key_len, + const std::vector& secret, + const std::vector& salt) const + { + return derive_key(key_len, + &secret[0], secret.size(), + &salt[0], salt.size()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param salt_len size of salt in bytes + */ + secure_vector derive_key(size_t key_len, + const secure_vector& secret, + const byte salt[], + size_t salt_len) const + { + return derive_key(key_len, + &secret[0], secret.size(), + salt, salt_len); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + */ + secure_vector derive_key(size_t key_len, + const byte secret[], + size_t secret_len, + const std::string& salt = "") const + { + return derive_key(key_len, secret, secret_len, + reinterpret_cast(salt.data()), + salt.length()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + */ + secure_vector derive_key(size_t key_len, + const byte secret[], + size_t secret_len, + const byte salt[], + size_t salt_len) const + { + return derive(key_len, secret, secret_len, salt, salt_len); + } + + void clear() {} + + virtual KDF* clone() const = 0; + private: + virtual secure_vector + derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const = 0; + }; + +/** +* Mask Generation Function +*/ +class BOTAN_DLL MGF + { + public: + virtual void mask(const byte in[], size_t in_len, + byte out[], size_t out_len) const = 0; + + virtual ~MGF() {} + }; + +/** +* Factory method for KDF (key derivation function) +* @param algo_spec the name of the KDF to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL KDF* get_kdf(const std::string& algo_spec); + +} + +#endif diff --git a/src/lib/kdf/kdf1/info.txt b/src/lib/kdf/kdf1/info.txt new file mode 100644 index 000000000..08192fa95 --- /dev/null +++ b/src/lib/kdf/kdf1/info.txt @@ -0,0 +1,5 @@ +define KDF1 20131128 + + +hash + diff --git a/src/lib/kdf/kdf1/kdf1.cpp b/src/lib/kdf/kdf1/kdf1.cpp new file mode 100644 index 000000000..f00f71010 --- /dev/null +++ b/src/lib/kdf/kdf1/kdf1.cpp @@ -0,0 +1,24 @@ +/* +* KDF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* KDF1 Key Derivation Mechanism +*/ +secure_vector KDF1::derive(size_t, + const byte secret[], size_t secret_len, + const byte P[], size_t P_len) const + { + hash->update(secret, secret_len); + hash->update(P, P_len); + return hash->final(); + } + +} diff --git a/src/lib/kdf/kdf1/kdf1.h b/src/lib/kdf/kdf1/kdf1.h new file mode 100644 index 000000000..6a14d2995 --- /dev/null +++ b/src/lib/kdf/kdf1/kdf1.h @@ -0,0 +1,39 @@ +/* +* KDF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KDF1_H__ +#define BOTAN_KDF1_H__ + +#include +#include + +namespace Botan { + +/** +* KDF1, from IEEE 1363 +*/ +class BOTAN_DLL KDF1 : public KDF + { + public: + secure_vector derive(size_t, + const byte secret[], size_t secret_len, + const byte P[], size_t P_len) const; + + std::string name() const { return "KDF1(" + hash->name() + ")"; } + KDF* clone() const { return new KDF1(hash->clone()); } + + KDF1(HashFunction* h) : hash(h) {} + KDF1(const KDF1& other) : KDF(), hash(other.hash->clone()) {} + + ~KDF1() { delete hash; } + private: + HashFunction* hash; + }; + +} + +#endif diff --git a/src/lib/kdf/kdf2/info.txt b/src/lib/kdf/kdf2/info.txt new file mode 100644 index 000000000..3481ff04f --- /dev/null +++ b/src/lib/kdf/kdf2/info.txt @@ -0,0 +1,5 @@ +define KDF2 20131128 + + +hash + diff --git a/src/lib/kdf/kdf2/kdf2.cpp b/src/lib/kdf/kdf2/kdf2.cpp new file mode 100644 index 000000000..39a929b58 --- /dev/null +++ b/src/lib/kdf/kdf2/kdf2.cpp @@ -0,0 +1,40 @@ +/* +* KDF2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* KDF2 Key Derivation Mechanism +*/ +secure_vector KDF2::derive(size_t out_len, + const byte secret[], size_t secret_len, + const byte P[], size_t P_len) const + { + secure_vector output; + u32bit counter = 1; + + while(out_len && counter) + { + hash->update(secret, secret_len); + hash->update_be(counter); + hash->update(P, P_len); + + secure_vector hash_result = hash->final(); + + size_t added = std::min(hash_result.size(), out_len); + output += std::make_pair(&hash_result[0], added); + out_len -= added; + + ++counter; + } + + return output; + } + +} diff --git a/src/lib/kdf/kdf2/kdf2.h b/src/lib/kdf/kdf2/kdf2.h new file mode 100644 index 000000000..e33939df9 --- /dev/null +++ b/src/lib/kdf/kdf2/kdf2.h @@ -0,0 +1,37 @@ +/* +* KDF2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KDF2_H__ +#define BOTAN_KDF2_H__ + +#include +#include + +namespace Botan { + +/** +* KDF2, from IEEE 1363 +*/ +class BOTAN_DLL KDF2 : public KDF + { + public: + secure_vector derive(size_t, const byte[], size_t, + const byte[], size_t) const; + + std::string name() const { return "KDF2(" + hash->name() + ")"; } + KDF* clone() const { return new KDF2(hash->clone()); } + + KDF2(HashFunction* h) : hash(h) {} + KDF2(const KDF2& other) : KDF(), hash(other.hash->clone()) {} + ~KDF2() { delete hash; } + private: + HashFunction* hash; + }; + +} + +#endif diff --git a/src/lib/kdf/mgf1/info.txt b/src/lib/kdf/mgf1/info.txt new file mode 100644 index 000000000..c6254b8a0 --- /dev/null +++ b/src/lib/kdf/mgf1/info.txt @@ -0,0 +1,5 @@ +define MGF1 20131128 + + +hash + diff --git a/src/lib/kdf/mgf1/mgf1.cpp b/src/lib/kdf/mgf1/mgf1.cpp new file mode 100644 index 000000000..e0433a02f --- /dev/null +++ b/src/lib/kdf/mgf1/mgf1.cpp @@ -0,0 +1,56 @@ +/* +* MGF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* MGF1 Mask Generation Function +*/ +void MGF1::mask(const byte in[], size_t in_len, byte out[], + size_t out_len) const + { + u32bit counter = 0; + + while(out_len) + { + hash->update(in, in_len); + hash->update_be(counter); + secure_vector buffer = hash->final(); + + size_t xored = std::min(buffer.size(), out_len); + xor_buf(out, &buffer[0], xored); + out += xored; + out_len -= xored; + + ++counter; + } + } + +/* +* MGF1 Constructor +*/ +MGF1::MGF1(HashFunction* h) : hash(h) + { + if(!hash) + throw Invalid_Argument("MGF1 given null hash object"); + } + +/* +* MGF1 Destructor +*/ +MGF1::~MGF1() + { + delete hash; + } + +} diff --git a/src/lib/kdf/mgf1/mgf1.h b/src/lib/kdf/mgf1/mgf1.h new file mode 100644 index 000000000..95a2a2bc5 --- /dev/null +++ b/src/lib/kdf/mgf1/mgf1.h @@ -0,0 +1,36 @@ +/* +* MGF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MGF1_H__ +#define BOTAN_MGF1_H__ + +#include +#include + +namespace Botan { + +/** +* MGF1 from PKCS #1 v2.0 +*/ +class BOTAN_DLL MGF1 : public MGF + { + public: + void mask(const byte[], size_t, byte[], size_t) const; + + /** + MGF1 constructor: takes ownership of hash + */ + MGF1(HashFunction* hash); + + ~MGF1(); + private: + HashFunction* hash; + }; + +} + +#endif diff --git a/src/lib/kdf/prf_ssl3/info.txt b/src/lib/kdf/prf_ssl3/info.txt new file mode 100644 index 000000000..c4e830bac --- /dev/null +++ b/src/lib/kdf/prf_ssl3/info.txt @@ -0,0 +1,7 @@ +define SSL_V3_PRF 20131128 + + +md5 +sha1 +algo_base + diff --git a/src/lib/kdf/prf_ssl3/prf_ssl3.cpp b/src/lib/kdf/prf_ssl3/prf_ssl3.cpp new file mode 100644 index 000000000..93901416f --- /dev/null +++ b/src/lib/kdf/prf_ssl3/prf_ssl3.cpp @@ -0,0 +1,76 @@ +/* +* SSLv3 PRF +* (C) 2004-2006 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Return the next inner hash +*/ +OctetString next_hash(size_t where, size_t want, + HashFunction& md5, HashFunction& sha1, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) + { + BOTAN_ASSERT(want <= md5.output_length(), + "Output size producable by MD5"); + + const byte ASCII_A_CHAR = 0x41; + + for(size_t j = 0; j != where + 1; j++) + sha1.update(static_cast(ASCII_A_CHAR + where)); + sha1.update(secret, secret_len); + sha1.update(seed, seed_len); + secure_vector sha1_hash = sha1.final(); + + md5.update(secret, secret_len); + md5.update(sha1_hash); + secure_vector md5_hash = md5.final(); + + return OctetString(&md5_hash[0], want); + } + +} + +/* +* SSL3 PRF +*/ +secure_vector SSL3_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const + { + if(key_len > 416) + throw Invalid_Argument("SSL3_PRF: Requested key length is too large"); + + MD5 md5; + SHA_160 sha1; + + OctetString output; + + int counter = 0; + while(key_len) + { + const size_t produce = std::min(key_len, md5.output_length()); + + output = output + next_hash(counter++, produce, md5, sha1, + secret, secret_len, seed, seed_len); + + key_len -= produce; + } + + return output.bits_of(); + } + +} diff --git a/src/lib/kdf/prf_ssl3/prf_ssl3.h b/src/lib/kdf/prf_ssl3/prf_ssl3.h new file mode 100644 index 000000000..bae8badb8 --- /dev/null +++ b/src/lib/kdf/prf_ssl3/prf_ssl3.h @@ -0,0 +1,30 @@ +/* +* SSLv3 PRF +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SSLV3_PRF_H__ +#define BOTAN_SSLV3_PRF_H__ + +#include + +namespace Botan { + +/** +* PRF used in SSLv3 +*/ +class BOTAN_DLL SSL3_PRF : public KDF + { + public: + secure_vector derive(size_t, const byte[], size_t, + const byte[], size_t) const; + + std::string name() const { return "SSL3-PRF"; } + KDF* clone() const { return new SSL3_PRF; } + }; + +} + +#endif diff --git a/src/lib/kdf/prf_tls/info.txt b/src/lib/kdf/prf_tls/info.txt new file mode 100644 index 000000000..505e1ff1e --- /dev/null +++ b/src/lib/kdf/prf_tls/info.txt @@ -0,0 +1,8 @@ +define TLS_V10_PRF 20131128 +define TLS_V12_PRF 20131128 + + +hmac +md5 +sha1 + diff --git a/src/lib/kdf/prf_tls/prf_tls.cpp b/src/lib/kdf/prf_tls/prf_tls.cpp new file mode 100644 index 000000000..006b418c9 --- /dev/null +++ b/src/lib/kdf/prf_tls/prf_tls.cpp @@ -0,0 +1,117 @@ +/* +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* TLS PRF P_hash function +*/ +void P_hash(secure_vector& output, + MessageAuthenticationCode* mac, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) + { + try + { + mac->set_key(secret, secret_len); + } + catch(Invalid_Key_Length) + { + throw Internal_Error("The premaster secret of " + + std::to_string(secret_len) + + " bytes is too long for the PRF"); + } + + secure_vector A(seed, seed + seed_len); + + size_t offset = 0; + + while(offset != output.size()) + { + const size_t this_block_len = + std::min(mac->output_length(), output.size() - offset); + + A = mac->process(A); + + mac->update(A); + mac->update(seed, seed_len); + secure_vector block = mac->final(); + + xor_buf(&output[offset], &block[0], this_block_len); + offset += this_block_len; + } + } + +} + +/* +* TLS PRF Constructor and Destructor +*/ +TLS_PRF::TLS_PRF() + { + hmac_md5 = new HMAC(new MD5); + hmac_sha1 = new HMAC(new SHA_160); + } + +TLS_PRF::~TLS_PRF() + { + delete hmac_md5; + delete hmac_sha1; + } + +/* +* TLS PRF +*/ +secure_vector TLS_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const + { + secure_vector output(key_len); + + size_t S1_len = (secret_len + 1) / 2, + S2_len = (secret_len + 1) / 2; + const byte* S1 = secret; + const byte* S2 = secret + (secret_len - S2_len); + + P_hash(output, hmac_md5, S1, S1_len, seed, seed_len); + P_hash(output, hmac_sha1, S2, S2_len, seed, seed_len); + + return output; + } + +/* +* TLS v1.2 PRF Constructor and Destructor +*/ +TLS_12_PRF::TLS_12_PRF(MessageAuthenticationCode* mac) : hmac(mac) + { + } + +TLS_12_PRF::~TLS_12_PRF() + { + delete hmac; + } + +secure_vector TLS_12_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const + { + secure_vector output(key_len); + + P_hash(output, hmac, secret, secret_len, seed, seed_len); + + return output; + } + +} diff --git a/src/lib/kdf/prf_tls/prf_tls.h b/src/lib/kdf/prf_tls/prf_tls.h new file mode 100644 index 000000000..fce11eae0 --- /dev/null +++ b/src/lib/kdf/prf_tls/prf_tls.h @@ -0,0 +1,58 @@ +/* +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_PRF_H__ +#define BOTAN_TLS_PRF_H__ + +#include +#include +#include + +namespace Botan { + +/** +* PRF used in TLS 1.0/1.1 +*/ +class BOTAN_DLL TLS_PRF : public KDF + { + public: + secure_vector derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const; + + std::string name() const { return "TLS-PRF"; } + KDF* clone() const { return new TLS_PRF; } + + TLS_PRF(); + ~TLS_PRF(); + private: + MessageAuthenticationCode* hmac_md5; + MessageAuthenticationCode* hmac_sha1; + }; + +/** +* PRF used in TLS 1.2 +*/ +class BOTAN_DLL TLS_12_PRF : public KDF + { + public: + secure_vector derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const; + + std::string name() const { return "TLSv12-PRF(" + hmac->name() + ")"; } + KDF* clone() const { return new TLS_12_PRF(hmac->clone()); } + + TLS_12_PRF(MessageAuthenticationCode* hmac); + ~TLS_12_PRF(); + private: + MessageAuthenticationCode* hmac; + }; + +} + +#endif diff --git a/src/lib/kdf/prf_x942/info.txt b/src/lib/kdf/prf_x942/info.txt new file mode 100644 index 000000000..ff4a6f160 --- /dev/null +++ b/src/lib/kdf/prf_x942/info.txt @@ -0,0 +1,7 @@ +define X942_PRF 20131128 + + +asn1 +oid_lookup +sha1 + diff --git a/src/lib/kdf/prf_x942/prf_x942.cpp b/src/lib/kdf/prf_x942/prf_x942.cpp new file mode 100644 index 000000000..149be163f --- /dev/null +++ b/src/lib/kdf/prf_x942/prf_x942.cpp @@ -0,0 +1,92 @@ +/* +* X9.42 PRF +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Encode an integer as an OCTET STRING +*/ +std::vector encode_x942_int(u32bit n) + { + byte n_buf[4] = { 0 }; + store_be(n, n_buf); + return DER_Encoder().encode(n_buf, 4, OCTET_STRING).get_contents_unlocked(); + } + +} + +/* +* X9.42 PRF +*/ +secure_vector X942_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + SHA_160 hash; + const OID kek_algo(key_wrap_oid); + + secure_vector key; + u32bit counter = 1; + + while(key.size() != key_len && counter) + { + hash.update(secret, secret_len); + + hash.update( + DER_Encoder().start_cons(SEQUENCE) + + .start_cons(SEQUENCE) + .encode(kek_algo) + .raw_bytes(encode_x942_int(counter)) + .end_cons() + + .encode_if(salt_len != 0, + DER_Encoder() + .start_explicit(0) + .encode(salt, salt_len, OCTET_STRING) + .end_explicit() + ) + + .start_explicit(2) + .raw_bytes(encode_x942_int(static_cast(8 * key_len))) + .end_explicit() + + .end_cons().get_contents() + ); + + secure_vector digest = hash.final(); + const size_t needed = std::min(digest.size(), key_len - key.size()); + key += std::make_pair(&digest[0], needed); + + ++counter; + } + + return key; + } + +/* +* X9.42 Constructor +*/ +X942_PRF::X942_PRF(const std::string& oid) + { + if(OIDS::have_oid(oid)) + key_wrap_oid = OIDS::lookup(oid).as_string(); + else + key_wrap_oid = oid; + } + +} diff --git a/src/lib/kdf/prf_x942/prf_x942.h b/src/lib/kdf/prf_x942/prf_x942.h new file mode 100644 index 000000000..f86b1bdd5 --- /dev/null +++ b/src/lib/kdf/prf_x942/prf_x942.h @@ -0,0 +1,34 @@ +/* +* X9.42 PRF +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ANSI_X942_PRF_H__ +#define BOTAN_ANSI_X942_PRF_H__ + +#include + +namespace Botan { + +/** +* PRF from ANSI X9.42 +*/ +class BOTAN_DLL X942_PRF : public KDF + { + public: + secure_vector derive(size_t, const byte[], size_t, + const byte[], size_t) const; + + std::string name() const { return "X942_PRF(" + key_wrap_oid + ")"; } + KDF* clone() const { return new X942_PRF(key_wrap_oid); } + + X942_PRF(const std::string& oid); + private: + std::string key_wrap_oid; + }; + +} + +#endif diff --git a/src/lib/libstate/botan.h b/src/lib/libstate/botan.h new file mode 100644 index 000000000..42d3dc392 --- /dev/null +++ b/src/lib/libstate/botan.h @@ -0,0 +1,23 @@ +/* +* A vague catch all include file for Botan +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BOTAN_H__ +#define BOTAN_BOTAN_H__ + +#include +#include +#include +#include +#include + +#include + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include +#endif + +#endif diff --git a/src/lib/libstate/global_rng.cpp b/src/lib/libstate/global_rng.cpp new file mode 100644 index 000000000..b6dc6b559 --- /dev/null +++ b/src/lib/libstate/global_rng.cpp @@ -0,0 +1,123 @@ +/* +* Global PRNG +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_EGD) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) + #include +#endif + +namespace Botan { + +std::vector> Library_State::entropy_sources() + { + std::vector> sources; + +#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER) + sources.push_back(std::unique_ptr(new High_Resolution_Timestamp)); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) + sources.push_back(std::unique_ptr(new Intel_Rdrand)); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) + sources.push_back(std::unique_ptr(new UnixProcessInfo_EntropySource)); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + sources.push_back(std::unique_ptr(new Device_EntropySource( + { "/dev/random", "/dev/srandom", "/dev/urandom" } + ))); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI) + sources.push_back(std::unique_ptr(new Win32_CAPI_EntropySource)); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) + sources.push_back(std::unique_ptr( + new ProcWalking_EntropySource("/proc"))); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + sources.push_back(std::unique_ptr(new Win32_EntropySource)); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS) + sources.push_back(std::unique_ptr(new BeOS_EntropySource)); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER) + sources.push_back(std::unique_ptr( + new Unix_EntropySource( + { "/bin", "/sbin", "/usr/bin", "/usr/sbin" } + ))); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_EGD) + sources.push_back(std::unique_ptr( + new EGD_EntropySource({ "/var/run/egd-pool", "/dev/egd-pool" }) + )); +#endif + + return sources; + } + +void Library_State::poll_available_sources(class Entropy_Accumulator& accum) + { + std::lock_guard lock(m_entropy_src_mutex); + + const size_t poll_bits = accum.desired_remaining_bits(); + + if(!m_sources.empty()) + { + size_t poll_attempt = 0; + + while(!accum.polling_goal_achieved() && poll_attempt < poll_bits) + { + const size_t src_idx = poll_attempt % m_sources.size(); + m_sources[src_idx]->poll(accum); + ++poll_attempt; + } + } + } + +} + diff --git a/src/lib/libstate/global_state.cpp b/src/lib/libstate/global_state.cpp new file mode 100644 index 000000000..6a846d9b0 --- /dev/null +++ b/src/lib/libstate/global_state.cpp @@ -0,0 +1,91 @@ +/* +* Global State Management +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* @todo There should probably be a lock to avoid racy manipulation +* of the state among different threads +*/ + +namespace Global_State_Management { + +/* +* Botan's global state +*/ +namespace { + +Library_State* global_lib_state = nullptr; + +} + +/* +* Access the global state object +*/ +Library_State& global_state() + { + /* Lazy initialization. Botan still needs to be deinitialized later + on or memory might leak. + */ + if(!global_lib_state) + { + global_lib_state = new Library_State; + global_lib_state->initialize(); + } + + return (*global_lib_state); + } + +/* +* Set a new global state object +*/ +void set_global_state(Library_State* new_state) + { + delete swap_global_state(new_state); + } + +/* +* Set a new global state object unless one already existed +*/ +bool set_global_state_unless_set(Library_State* new_state) + { + if(global_lib_state) + { + delete new_state; + return false; + } + else + { + delete swap_global_state(new_state); + return true; + } + } + +/* +* Swap two global state objects +*/ +Library_State* swap_global_state(Library_State* new_state) + { + Library_State* old_state = global_lib_state; + global_lib_state = new_state; + return old_state; + } + +/* +* Query if library is initialized +*/ +bool global_state_exists() + { + return (global_lib_state != nullptr); + } + +} + +} diff --git a/src/lib/libstate/global_state.h b/src/lib/libstate/global_state.h new file mode 100644 index 000000000..486aed17e --- /dev/null +++ b/src/lib/libstate/global_state.h @@ -0,0 +1,69 @@ +/* +* Global State Management +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GLOBAL_STATE_H__ +#define BOTAN_GLOBAL_STATE_H__ + +#include + +namespace Botan { + +/* +* Forward declare to avoid recursive dependency between this header +* and libstate.h +*/ +class Library_State; + +/** +* Namespace for management of the global state +*/ +namespace Global_State_Management { + +/** +* Access the global library state +* @return reference to the global library state +*/ +BOTAN_DLL Library_State& global_state(); + +/** +* Set the global state object +* @param state the new global state to use +*/ +BOTAN_DLL void set_global_state(Library_State* state); + +/** +* Set the global state object unless it is already set +* @param state the new global state to use +* @return true if the state parameter is now being used as the global +* state, or false if one was already set, in which case the +* parameter was deleted immediately +*/ +BOTAN_DLL bool set_global_state_unless_set(Library_State* state); + +/** +* Swap the current state for another +* @param new_state the new state object to use +* @return previous state (or NULL if none) +*/ +BOTAN_DLL Library_State* swap_global_state(Library_State* new_state); + +/** +* Query if the library is currently initialized +* @return true iff the library is initialized +*/ +BOTAN_DLL bool global_state_exists(); + +} + +/* +* Insert into Botan ns for convenience/backwards compatability +*/ +using Global_State_Management::global_state; + +} + +#endif diff --git a/src/lib/libstate/info.txt b/src/lib/libstate/info.txt new file mode 100644 index 000000000..49a6d38ee --- /dev/null +++ b/src/lib/libstate/info.txt @@ -0,0 +1,21 @@ +load_on always + + +algo_factory +alloc +bigint +block +core_engine +engine +filters +hash +hmac +kdf +mac +mode_pad +pbkdf +pk_pad +pubkey +rng +stream + diff --git a/src/lib/libstate/init.cpp b/src/lib/libstate/init.cpp new file mode 100644 index 000000000..2d724f366 --- /dev/null +++ b/src/lib/libstate/init.cpp @@ -0,0 +1,47 @@ +/* +* Default Initialization Function +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Library Initialization +*/ +void LibraryInitializer::initialize(const std::string&) + { + + try + { + /* + This two stage initialization process is because Library_State's + constructor will implicitly refer to global state through the + allocators and so forth, so global_state() has to be a valid + reference before initialize() can be called. Yeah, gross. + */ + Global_State_Management::set_global_state(new Library_State); + + global_state().initialize(); + } + catch(...) + { + deinitialize(); + throw; + } + } + +/* +* Library Shutdown +*/ +void LibraryInitializer::deinitialize() + { + Global_State_Management::set_global_state(nullptr); + } + +} diff --git a/src/lib/libstate/init.h b/src/lib/libstate/init.h new file mode 100644 index 000000000..2d70e4370 --- /dev/null +++ b/src/lib/libstate/init.h @@ -0,0 +1,48 @@ +/* +* Library Initialization +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LIBRARY_INITIALIZER_H__ +#define BOTAN_LIBRARY_INITIALIZER_H__ + +#include +#include + +namespace Botan { + +/** +* This class represents the Library Initialization/Shutdown Object. It +* has to exceed the lifetime of any Botan object used in an +* application. You can call initialize/deinitialize or use +* LibraryInitializer in the RAII style. +*/ +class BOTAN_DLL LibraryInitializer + { + public: + /** + * Initialize the library + * @param options a string listing initialization options + */ + static void initialize(const std::string& options = ""); + + /** + * Shutdown the library + */ + static void deinitialize(); + + /** + * Initialize the library + * @param options a string listing initialization options + */ + LibraryInitializer(const std::string& options = "") + { LibraryInitializer::initialize(options); } + + ~LibraryInitializer() { LibraryInitializer::deinitialize(); } + }; + +} + +#endif diff --git a/src/lib/libstate/libstate.cpp b/src/lib/libstate/libstate.cpp new file mode 100644 index 000000000..649dcc9b4 --- /dev/null +++ b/src/lib/libstate/libstate.cpp @@ -0,0 +1,104 @@ +/* +* Library Internal/Global State +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_SELFTESTS) + #include +#endif + +#if defined(BOTAN_HAS_ENGINE_ASSEMBLER) + #include +#endif + +#if defined(BOTAN_HAS_ENGINE_AES_ISA) + #include +#endif + +#if defined(BOTAN_HAS_ENGINE_SIMD) + #include +#endif + +#if defined(BOTAN_HAS_ENGINE_GNU_MP) + #include +#endif + +#if defined(BOTAN_HAS_ENGINE_OPENSSL) + #include +#endif + +namespace Botan { + +/* +* Return a reference to the Algorithm_Factory +*/ +Algorithm_Factory& Library_State::algorithm_factory() const + { + if(!m_algorithm_factory) + throw Invalid_State("Uninitialized in Library_State::algorithm_factory"); + return *m_algorithm_factory; + } + +/* +* Return a reference to the global PRNG +*/ +RandomNumberGenerator& Library_State::global_rng() + { + return *m_global_prng; + } + +void Library_State::initialize() + { + if(m_algorithm_factory.get()) + throw Invalid_State("Library_State has already been initialized"); + + CPUID::initialize(); + + SCAN_Name::set_default_aliases(); + OIDS::set_defaults(); + + m_algorithm_factory.reset(new Algorithm_Factory()); + +#if defined(BOTAN_HAS_ENGINE_GNU_MP) + algorithm_factory().add_engine(new GMP_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_OPENSSL) + algorithm_factory().add_engine(new OpenSSL_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_AES_ISA) + algorithm_factory().add_engine(new AES_ISA_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_SIMD) + algorithm_factory().add_engine(new SIMD_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_ASSEMBLER) + algorithm_factory().add_engine(new Assembler_Engine); +#endif + + algorithm_factory().add_engine(new Core_Engine); + + m_sources = entropy_sources(); + + m_global_prng.reset(new Serialized_RNG()); + +#if defined(BOTAN_HAS_SELFTESTS) + confirm_startup_self_tests(algorithm_factory()); +#endif + } + +} diff --git a/src/lib/libstate/libstate.h b/src/lib/libstate/libstate.h new file mode 100644 index 000000000..d8734966a --- /dev/null +++ b/src/lib/libstate/libstate.h @@ -0,0 +1,60 @@ +/* +* Library Internal/Global State +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LIB_STATE_H__ +#define BOTAN_LIB_STATE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Global Library State +*/ +class BOTAN_DLL Library_State + { + public: + Library_State() {} + + Library_State(const Library_State&) = delete; + Library_State& operator=(const Library_State&) = delete; + + void initialize(); + + /** + * @return global Algorithm_Factory + */ + Algorithm_Factory& algorithm_factory() const; + + /** + * @return global RandomNumberGenerator + */ + RandomNumberGenerator& global_rng(); + + void poll_available_sources(class Entropy_Accumulator& accum); + + private: + static std::vector> entropy_sources(); + + std::unique_ptr m_global_prng; + + std::mutex m_entropy_src_mutex; + std::vector> m_sources; + + std::unique_ptr m_algorithm_factory; + }; + +} + +#endif diff --git a/src/lib/libstate/lookup.cpp b/src/lib/libstate/lookup.cpp new file mode 100644 index 000000000..85f93bb95 --- /dev/null +++ b/src/lib/libstate/lookup.cpp @@ -0,0 +1,124 @@ +/* +* Algorithm Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Get a PBKDF algorithm by name +*/ +PBKDF* get_pbkdf(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(PBKDF* pbkdf = af.make_pbkdf(algo_spec)) + return pbkdf; + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Query if an algorithm exists +*/ +bool have_algorithm(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(af.prototype_block_cipher(name)) + return true; + if(af.prototype_stream_cipher(name)) + return true; + if(af.prototype_hash_function(name)) + return true; + if(af.prototype_mac(name)) + return true; + return false; + } + +/* +* Query the block size of a cipher or hash +*/ +size_t block_size_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* cipher = af.prototype_block_cipher(name)) + return cipher->block_size(); + + if(const HashFunction* hash = af.prototype_hash_function(name)) + return hash->hash_block_size(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the output_length() of a hash or MAC +*/ +size_t output_length_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const HashFunction* hash = af.prototype_hash_function(name)) + return hash->output_length(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->output_length(); + + throw Algorithm_Not_Found(name); + } + +/* +* Get a cipher object +*/ +Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + Algorithm_Factory::Engine_Iterator i(af); + + while(Engine* engine = i.next()) + { + if(Keyed_Filter* algo = engine->get_cipher(algo_spec, direction, af)) + return algo; + } + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get a cipher object +*/ +Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction) + { + Keyed_Filter* cipher = get_cipher(algo_spec, direction); + cipher->set_key(key); + + if(iv.length()) + cipher->set_iv(iv); + + return cipher; + } + +/* +* Get a cipher object +*/ +Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction) + { + return get_cipher(algo_spec, + key, InitializationVector(), direction); + } + +} diff --git a/src/lib/libstate/lookup.h b/src/lib/libstate/lookup.h new file mode 100644 index 000000000..e0024c224 --- /dev/null +++ b/src/lib/libstate/lookup.h @@ -0,0 +1,276 @@ +/* +* Algorithm Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LOOKUP_H__ +#define BOTAN_LOOKUP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const BlockCipher* +retrieve_block_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_block_cipher(algo_spec); + } + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const StreamCipher* +retrieve_stream_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_stream_cipher(algo_spec); + } + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const HashFunction* +retrieve_hash(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_hash_function(algo_spec); + } + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const MessageAuthenticationCode* +retrieve_mac(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_mac(algo_spec); + } + +/* +* Get an algorithm object +* NOTE: these functions create and return new objects, letting the +* caller assume ownership of them +*/ + +/** +* Block cipher factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired block cipher +* @return pointer to the block cipher object +*/ +inline BlockCipher* get_block_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_block_cipher(algo_spec); + } + +/** +* Stream cipher factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired stream cipher +* @return pointer to the stream cipher object +*/ +inline StreamCipher* get_stream_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_stream_cipher(algo_spec); + } + +/** +* Hash function factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired hash function +* @return pointer to the hash function object +*/ +inline HashFunction* get_hash(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_hash_function(algo_spec); + } + +/** +* MAC factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired MAC +* @return pointer to the MAC object +*/ +inline MessageAuthenticationCode* get_mac(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_mac(algo_spec); + } + +/** +* Password based key derivation function factory method +* @param algo_spec the name of the desired PBKDF algorithm +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL PBKDF* get_pbkdf(const std::string& algo_spec); + +/** +* @deprecated Use get_pbkdf +* @param algo_spec the name of the desired algorithm +* @return pointer to newly allocated object of that type +*/ +inline PBKDF* get_s2k(const std::string& algo_spec) + { + return get_pbkdf(algo_spec); + } + +/* +* Get a cipher object +*/ + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param iv the initialization vector to be used +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to newly allocated encryption or decryption filter +*/ +BOTAN_DLL Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction); + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to the encryption or decryption filter +*/ +BOTAN_DLL Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction); + +/** +* Factory method for general symmetric cipher filters. No key will be +* set in the filter. +* +* @param algo_spec the name of the desired cipher +* @param direction determines whether the filter will be an encrypting or +* decrypting filter +* @return pointer to the encryption or decryption filter +*/ +BOTAN_DLL Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction); + +/** +* Check if an algorithm exists. +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +BOTAN_DLL bool have_algorithm(const std::string& algo_spec); + +/** +* Check if a block cipher algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_block_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_block_cipher(algo_spec) != nullptr); + } + +/** +* Check if a stream cipher algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_stream_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_stream_cipher(algo_spec) != nullptr); + } + +/** +* Check if a hash algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_hash(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_hash_function(algo_spec) != nullptr); + } + +/** +* Check if a MAC algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_mac(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_mac(algo_spec) != nullptr); + } + +/* +* Query information about an algorithm +*/ + +/** +* Find out the block size of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return block size of the specified algorithm +*/ +BOTAN_DLL size_t block_size_of(const std::string& algo_spec); + +/** +* Find out the output length of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return output length of the specified algorithm +*/ +BOTAN_DLL size_t output_length_of(const std::string& algo_spec); + +} + +#endif diff --git a/src/lib/mac/cbc_mac/cbc_mac.cpp b/src/lib/mac/cbc_mac/cbc_mac.cpp new file mode 100644 index 000000000..118570e72 --- /dev/null +++ b/src/lib/mac/cbc_mac/cbc_mac.cpp @@ -0,0 +1,105 @@ +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Update an CBC-MAC Calculation +*/ +void CBC_MAC::add_data(const byte input[], size_t length) + { + size_t xored = std::min(output_length() - position, length); + xor_buf(&state[position], input, xored); + position += xored; + + if(position < output_length()) + return; + + e->encrypt(state); + input += xored; + length -= xored; + while(length >= output_length()) + { + xor_buf(state, input, output_length()); + e->encrypt(state); + input += output_length(); + length -= output_length(); + } + + xor_buf(state, input, length); + position = length; + } + +/* +* Finalize an CBC-MAC Calculation +*/ +void CBC_MAC::final_result(byte mac[]) + { + if(position) + e->encrypt(state); + + copy_mem(mac, &state[0], state.size()); + zeroise(state); + position = 0; + } + +/* +* CBC-MAC Key Schedule +*/ +void CBC_MAC::key_schedule(const byte key[], size_t length) + { + e->set_key(key, length); + } + +/* +* Clear memory of sensitive data +*/ +void CBC_MAC::clear() + { + e->clear(); + zeroise(state); + position = 0; + } + +/* +* Return the name of this type +*/ +std::string CBC_MAC::name() const + { + return "CBC-MAC(" + e->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CBC_MAC::clone() const + { + return new CBC_MAC(e->clone()); + } + +/* +* CBC-MAC Constructor +*/ +CBC_MAC::CBC_MAC(BlockCipher* e_in) : + e(e_in), state(e->block_size()) + { + position = 0; + } + +/* +* CBC-MAC Destructor +*/ +CBC_MAC::~CBC_MAC() + { + delete e; + } + +} diff --git a/src/lib/mac/cbc_mac/cbc_mac.h b/src/lib/mac/cbc_mac/cbc_mac.h new file mode 100644 index 000000000..be25718d9 --- /dev/null +++ b/src/lib/mac/cbc_mac/cbc_mac.h @@ -0,0 +1,49 @@ +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CBC_MAC_H__ +#define BOTAN_CBC_MAC_H__ + +#include +#include + +namespace Botan { + +/** +* CBC-MAC +*/ +class BOTAN_DLL CBC_MAC : public MessageAuthenticationCode + { + public: + std::string name() const; + MessageAuthenticationCode* clone() const; + size_t output_length() const { return e->block_size(); } + void clear(); + + Key_Length_Specification key_spec() const + { + return e->key_spec(); + } + + /** + * @param cipher the underlying block cipher to use + */ + CBC_MAC(BlockCipher* cipher); + ~CBC_MAC(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + BlockCipher* e; + secure_vector state; + size_t position; + }; + +} + +#endif diff --git a/src/lib/mac/cbc_mac/info.txt b/src/lib/mac/cbc_mac/info.txt new file mode 100644 index 000000000..cb017e2a1 --- /dev/null +++ b/src/lib/mac/cbc_mac/info.txt @@ -0,0 +1,5 @@ +define CBC_MAC 20131128 + + +block + diff --git a/src/lib/mac/cmac/cmac.cpp b/src/lib/mac/cmac/cmac.cpp new file mode 100644 index 000000000..00120cf14 --- /dev/null +++ b/src/lib/mac/cmac/cmac.cpp @@ -0,0 +1,156 @@ +/* +* CMAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Perform CMAC's multiplication in GF(2^n) +*/ +secure_vector CMAC::poly_double(const secure_vector& in, + byte polynomial) + { + const byte poly_xor = (in[0] & 0x80) ? polynomial : 0; + + secure_vector out = in; + + byte carry = 0; + for(size_t i = out.size(); i != 0; --i) + { + byte temp = out[i-1]; + out[i-1] = (temp << 1) | carry; + carry = (temp >> 7); + } + + out[out.size()-1] ^= poly_xor; + + return out; + } + +/* +* Update an CMAC Calculation +*/ +void CMAC::add_data(const byte input[], size_t length) + { + buffer_insert(buffer, position, input, length); + if(position + length > output_length()) + { + xor_buf(state, buffer, output_length()); + e->encrypt(state); + input += (output_length() - position); + length -= (output_length() - position); + while(length > output_length()) + { + xor_buf(state, input, output_length()); + e->encrypt(state); + input += output_length(); + length -= output_length(); + } + copy_mem(&buffer[0], input, length); + position = 0; + } + position += length; + } + +/* +* Finalize an CMAC Calculation +*/ +void CMAC::final_result(byte mac[]) + { + xor_buf(state, buffer, position); + + if(position == output_length()) + { + xor_buf(state, B, output_length()); + } + else + { + state[position] ^= 0x80; + xor_buf(state, P, output_length()); + } + + e->encrypt(state); + + for(size_t i = 0; i != output_length(); ++i) + mac[i] = state[i]; + + zeroise(state); + zeroise(buffer); + position = 0; + } + +/* +* CMAC Key Schedule +*/ +void CMAC::key_schedule(const byte key[], size_t length) + { + clear(); + e->set_key(key, length); + e->encrypt(B); + B = poly_double(B, polynomial); + P = poly_double(B, polynomial); + } + +/* +* Clear memory of sensitive data +*/ +void CMAC::clear() + { + e->clear(); + zeroise(state); + zeroise(buffer); + zeroise(B); + zeroise(P); + position = 0; + } + +/* +* Return the name of this type +*/ +std::string CMAC::name() const + { + return "CMAC(" + e->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CMAC::clone() const + { + return new CMAC(e->clone()); + } + +/* +* CMAC Constructor +*/ +CMAC::CMAC(BlockCipher* e_in) : e(e_in) + { + if(e->block_size() == 16) + polynomial = 0x87; + else if(e->block_size() == 8) + polynomial = 0x1B; + else + throw Invalid_Argument("CMAC cannot use the cipher " + e->name()); + + state.resize(output_length()); + buffer.resize(output_length()); + B.resize(output_length()); + P.resize(output_length()); + position = 0; + } + +/* +* CMAC Destructor +*/ +CMAC::~CMAC() + { + delete e; + } + +} diff --git a/src/lib/mac/cmac/cmac.h b/src/lib/mac/cmac/cmac.h new file mode 100644 index 000000000..c1b75cfa5 --- /dev/null +++ b/src/lib/mac/cmac/cmac.h @@ -0,0 +1,63 @@ +/* +* CMAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CMAC_H__ +#define BOTAN_CMAC_H__ + +#include +#include + +namespace Botan { + +/** +* CMAC, also known as OMAC1 +*/ +class BOTAN_DLL CMAC : public MessageAuthenticationCode + { + public: + std::string name() const; + size_t output_length() const { return e->block_size(); } + MessageAuthenticationCode* clone() const; + + void clear(); + + Key_Length_Specification key_spec() const + { + return e->key_spec(); + } + + /** + * CMAC's polynomial doubling operation + * @param in the input + * @param polynomial the byte value of the polynomial + */ + static secure_vector poly_double(const secure_vector& in, + byte polynomial); + + /** + * @param cipher the underlying block cipher to use + */ + CMAC(BlockCipher* cipher); + + CMAC(const CMAC&) = delete; + CMAC& operator=(const CMAC&) = delete; + + ~CMAC(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + BlockCipher* e; + secure_vector buffer, state, B, P; + size_t position; + byte polynomial; + }; + +} + +#endif diff --git a/src/lib/mac/cmac/info.txt b/src/lib/mac/cmac/info.txt new file mode 100644 index 000000000..d2dc6f68d --- /dev/null +++ b/src/lib/mac/cmac/info.txt @@ -0,0 +1,5 @@ +define CMAC 20131128 + + +block + diff --git a/src/lib/mac/hmac/hmac.cpp b/src/lib/mac/hmac/hmac.cpp new file mode 100644 index 000000000..9e9a643db --- /dev/null +++ b/src/lib/mac/hmac/hmac.cpp @@ -0,0 +1,97 @@ +/* +* HMAC +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Update a HMAC Calculation +*/ +void HMAC::add_data(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Finalize a HMAC Calculation +*/ +void HMAC::final_result(byte mac[]) + { + hash->final(mac); + hash->update(o_key); + hash->update(mac, output_length()); + hash->final(mac); + hash->update(i_key); + } + +/* +* HMAC Key Schedule +*/ +void HMAC::key_schedule(const byte key[], size_t length) + { + hash->clear(); + + i_key.resize(hash->hash_block_size()); + o_key.resize(hash->hash_block_size()); + + std::fill(i_key.begin(), i_key.end(), 0x36); + std::fill(o_key.begin(), o_key.end(), 0x5C); + + if(length > hash->hash_block_size()) + { + secure_vector hmac_key = hash->process(key, length); + xor_buf(i_key, hmac_key, hmac_key.size()); + xor_buf(o_key, hmac_key, hmac_key.size()); + } + else + { + xor_buf(i_key, key, length); + xor_buf(o_key, key, length); + } + + hash->update(i_key); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC::clear() + { + hash->clear(); + zap(i_key); + zap(o_key); + } + +/* +* Return the name of this type +*/ +std::string HMAC::name() const + { + return "HMAC(" + hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* HMAC::clone() const + { + return new HMAC(hash->clone()); + } + +/* +* HMAC Constructor +*/ +HMAC::HMAC(HashFunction* hash_in) : hash(hash_in) + { + if(hash->hash_block_size() == 0) + throw Invalid_Argument("HMAC cannot be used with " + hash->name()); + } + +} diff --git a/src/lib/mac/hmac/hmac.h b/src/lib/mac/hmac/hmac.h new file mode 100644 index 000000000..39a084874 --- /dev/null +++ b/src/lib/mac/hmac/hmac.h @@ -0,0 +1,53 @@ +/* +* HMAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HMAC_H__ +#define BOTAN_HMAC_H__ + +#include +#include + +namespace Botan { + +/** +* HMAC +*/ +class BOTAN_DLL HMAC : public MessageAuthenticationCode + { + public: + void clear(); + std::string name() const; + MessageAuthenticationCode* clone() const; + + size_t output_length() const { return hash->output_length(); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(0, 512); + } + + /** + * @param hash the hash to use for HMACing + */ + HMAC(HashFunction* hash); + + HMAC(const HMAC&) = delete; + HMAC& operator=(const HMAC&) = delete; + + ~HMAC() { delete hash; } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + HashFunction* hash; + secure_vector i_key, o_key; + }; + +} + +#endif diff --git a/src/lib/mac/hmac/info.txt b/src/lib/mac/hmac/info.txt new file mode 100644 index 000000000..7bc8b27f8 --- /dev/null +++ b/src/lib/mac/hmac/info.txt @@ -0,0 +1,5 @@ +define HMAC 20131128 + + +hash + diff --git a/src/lib/mac/info.txt b/src/lib/mac/info.txt new file mode 100644 index 000000000..d991577f7 --- /dev/null +++ b/src/lib/mac/info.txt @@ -0,0 +1,3 @@ + +algo_base + diff --git a/src/lib/mac/mac.cpp b/src/lib/mac/mac.cpp new file mode 100644 index 000000000..094aa1b4a --- /dev/null +++ b/src/lib/mac/mac.cpp @@ -0,0 +1,26 @@ +/* +* Message Authentication Code base class +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Default (deterministic) MAC verification operation +*/ +bool MessageAuthenticationCode::verify_mac(const byte mac[], size_t length) + { + secure_vector our_mac = final(); + + if(our_mac.size() != length) + return false; + + return same_mem(&our_mac[0], &mac[0], length); + } + +} diff --git a/src/lib/mac/mac.h b/src/lib/mac/mac.h new file mode 100644 index 000000000..d42092908 --- /dev/null +++ b/src/lib/mac/mac.h @@ -0,0 +1,46 @@ +/* +* Base class for message authentiction codes +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MESSAGE_AUTH_CODE_BASE_H__ +#define BOTAN_MESSAGE_AUTH_CODE_BASE_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents Message Authentication Code (MAC) objects. +*/ +class BOTAN_DLL MessageAuthenticationCode : public Buffered_Computation, + public SymmetricAlgorithm + { + public: + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @param length the length of param in + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const byte in[], size_t length); + + /** + * Get a new object representing the same algorithm as *this + */ + virtual MessageAuthenticationCode* clone() const = 0; + + /** + * Get the name of this algorithm. + * @return name of this algorithm + */ + virtual std::string name() const = 0; + }; + +} + +#endif diff --git a/src/lib/mac/ssl3mac/info.txt b/src/lib/mac/ssl3mac/info.txt new file mode 100644 index 000000000..5e69b0ae8 --- /dev/null +++ b/src/lib/mac/ssl3mac/info.txt @@ -0,0 +1,5 @@ +define SSL3_MAC 20131128 + + +hash + diff --git a/src/lib/mac/ssl3mac/ssl3_mac.cpp b/src/lib/mac/ssl3mac/ssl3_mac.cpp new file mode 100644 index 000000000..64f3103ef --- /dev/null +++ b/src/lib/mac/ssl3mac/ssl3_mac.cpp @@ -0,0 +1,90 @@ +/* +* SSL3-MAC +* (C) 1999-2004 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Update a SSL3-MAC Calculation +*/ +void SSL3_MAC::add_data(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Finalize a SSL3-MAC Calculation +*/ +void SSL3_MAC::final_result(byte mac[]) + { + hash->final(mac); + hash->update(o_key); + hash->update(mac, output_length()); + hash->final(mac); + hash->update(i_key); + } + +/* +* SSL3-MAC Key Schedule +*/ +void SSL3_MAC::key_schedule(const byte key[], size_t length) + { + hash->clear(); + + // Quirk to deal with specification bug + const size_t inner_hash_length = + (hash->name() == "SHA-160") ? 60 : hash->hash_block_size(); + + i_key.resize(inner_hash_length); + o_key.resize(inner_hash_length); + + std::fill(i_key.begin(), i_key.end(), 0x36); + std::fill(o_key.begin(), o_key.end(), 0x5C); + + copy_mem(&i_key[0], key, length); + copy_mem(&o_key[0], key, length); + + hash->update(i_key); + } + +/* +* Clear memory of sensitive data +*/ +void SSL3_MAC::clear() + { + hash->clear(); + zap(i_key); + zap(o_key); + } + +/* +* Return the name of this type +*/ +std::string SSL3_MAC::name() const + { + return "SSL3-MAC(" + hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* SSL3_MAC::clone() const + { + return new SSL3_MAC(hash->clone()); + } + +/* +* SSL3-MAC Constructor +*/ +SSL3_MAC::SSL3_MAC(HashFunction* hash_in) : hash(hash_in) + { + if(hash->hash_block_size() == 0) + throw Invalid_Argument("SSL3-MAC cannot be used with " + hash->name()); + } + +} diff --git a/src/lib/mac/ssl3mac/ssl3_mac.h b/src/lib/mac/ssl3mac/ssl3_mac.h new file mode 100644 index 000000000..d23ac023c --- /dev/null +++ b/src/lib/mac/ssl3mac/ssl3_mac.h @@ -0,0 +1,49 @@ +/* +* SSL3-MAC +* (C) 1999-2004 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SSL3_MAC_H__ +#define BOTAN_SSL3_MAC_H__ + +#include +#include + +namespace Botan { + +/** +* A MAC only used in SSLv3. Do not use elsewhere! Use HMAC instead. +*/ +class BOTAN_DLL SSL3_MAC : public MessageAuthenticationCode + { + public: + std::string name() const; + size_t output_length() const { return hash->output_length(); } + MessageAuthenticationCode* clone() const; + + void clear(); + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(hash->output_length()); + } + + /** + * @param hash the underlying hash to use + */ + SSL3_MAC(HashFunction* hash); + ~SSL3_MAC() { delete hash; } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + HashFunction* hash; + secure_vector i_key, o_key; + }; + +} + +#endif diff --git a/src/lib/mac/x919_mac/info.txt b/src/lib/mac/x919_mac/info.txt new file mode 100644 index 000000000..63bf40790 --- /dev/null +++ b/src/lib/mac/x919_mac/info.txt @@ -0,0 +1,5 @@ +define ANSI_X919_MAC 20131128 + + +block + diff --git a/src/lib/mac/x919_mac/x919_mac.cpp b/src/lib/mac/x919_mac/x919_mac.cpp new file mode 100644 index 000000000..faf6138ef --- /dev/null +++ b/src/lib/mac/x919_mac/x919_mac.cpp @@ -0,0 +1,103 @@ +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Update an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::add_data(const byte input[], size_t length) + { + size_t xored = std::min(8 - position, length); + xor_buf(&state[position], input, xored); + position += xored; + + if(position < 8) return; + + e->encrypt(state); + input += xored; + length -= xored; + while(length >= 8) + { + xor_buf(state, input, 8); + e->encrypt(state); + input += 8; + length -= 8; + } + + xor_buf(state, input, length); + position = length; + } + +/* +* Finalize an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::final_result(byte mac[]) + { + if(position) + e->encrypt(state); + d->decrypt(&state[0], mac); + e->encrypt(mac); + zeroise(state); + position = 0; + } + +/* +* ANSI X9.19 MAC Key Schedule +*/ +void ANSI_X919_MAC::key_schedule(const byte key[], size_t length) + { + e->set_key(key, 8); + if(length == 8) d->set_key(key, 8); + else d->set_key(key + 8, 8); + } + +/* +* Clear memory of sensitive data +*/ +void ANSI_X919_MAC::clear() + { + e->clear(); + d->clear(); + zeroise(state); + position = 0; + } + +std::string ANSI_X919_MAC::name() const + { + return "X9.19-MAC"; + } + +MessageAuthenticationCode* ANSI_X919_MAC::clone() const + { + return new ANSI_X919_MAC(e->clone()); + } + +/* +* ANSI X9.19 MAC Constructor +*/ +ANSI_X919_MAC::ANSI_X919_MAC(BlockCipher* e_in) : + e(e_in), d(e->clone()), state(e->block_size()), position(0) + { + if(e->name() != "DES") + throw Invalid_Argument("ANSI X9.19 MAC only supports DES"); + } + +/* +* ANSI X9.19 MAC Destructor +le*/ +ANSI_X919_MAC::~ANSI_X919_MAC() + { + delete e; + delete d; + } + +} diff --git a/src/lib/mac/x919_mac/x919_mac.h b/src/lib/mac/x919_mac/x919_mac.h new file mode 100644 index 000000000..b7b7d685e --- /dev/null +++ b/src/lib/mac/x919_mac/x919_mac.h @@ -0,0 +1,54 @@ +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ANSI_X919_MAC_H__ +#define BOTAN_ANSI_X919_MAC_H__ + +#include +#include + +namespace Botan { + +/** +* DES/3DES-based MAC from ANSI X9.19 +*/ +class BOTAN_DLL ANSI_X919_MAC : public MessageAuthenticationCode + { + public: + void clear(); + std::string name() const; + size_t output_length() const { return e->block_size(); } + MessageAuthenticationCode* clone() const; + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(8, 16, 8); + } + + /** + * @param cipher the underlying block cipher to use + */ + ANSI_X919_MAC(BlockCipher* cipher); + + ANSI_X919_MAC(const ANSI_X919_MAC&) = delete; + ANSI_X919_MAC& operator=(const ANSI_X919_MAC&) = delete; + + ~ANSI_X919_MAC(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + BlockCipher* e; + BlockCipher* d; + secure_vector state; + size_t position; + }; + +} + +#endif diff --git a/src/lib/math/bigint/big_code.cpp b/src/lib/math/bigint/big_code.cpp new file mode 100644 index 000000000..972312cdb --- /dev/null +++ b/src/lib/math/bigint/big_code.cpp @@ -0,0 +1,150 @@ +/* +* BigInt Encoding/Decoding +* (C) 1999-2010,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Encode a BigInt +*/ +void BigInt::encode(byte output[], const BigInt& n, Base base) + { + if(base == Binary) + { + n.binary_encode(output); + } + else if(base == Hexadecimal) + { + secure_vector binary(n.encoded_size(Binary)); + n.binary_encode(&binary[0]); + + hex_encode(reinterpret_cast(output), + &binary[0], binary.size()); + } + else if(base == Decimal) + { + BigInt copy = n; + BigInt remainder; + copy.set_sign(Positive); + const size_t output_size = n.encoded_size(Decimal); + for(size_t j = 0; j != output_size; ++j) + { + divide(copy, 10, copy, remainder); + output[output_size - 1 - j] = + Charset::digit2char(static_cast(remainder.word_at(0))); + if(copy.is_zero()) + break; + } + } + else + throw Invalid_Argument("Unknown BigInt encoding method"); + } + +/* +* Encode a BigInt +*/ +std::vector BigInt::encode(const BigInt& n, Base base) + { + std::vector output(n.encoded_size(base)); + encode(&output[0], n, base); + if(base != Binary) + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; + } + +/* +* Encode a BigInt +*/ +secure_vector BigInt::encode_locked(const BigInt& n, Base base) + { + secure_vector output(n.encoded_size(base)); + encode(&output[0], n, base); + if(base != Binary) + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; + } + +/* +* Encode a BigInt, with leading 0s if needed +*/ +secure_vector BigInt::encode_1363(const BigInt& n, size_t bytes) + { + const size_t n_bytes = n.bytes(); + if(n_bytes > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + const size_t leading_0s = bytes - n_bytes; + + secure_vector output(bytes); + encode(&output[leading_0s], n, Binary); + return output; + } + +/* +* Decode a BigInt +*/ +BigInt BigInt::decode(const byte buf[], size_t length, Base base) + { + BigInt r; + if(base == Binary) + r.binary_decode(buf, length); + else if(base == Hexadecimal) + { + secure_vector binary; + + if(length % 2) + { + // Handle lack of leading 0 + const char buf0_with_leading_0[2] = + { '0', static_cast(buf[0]) }; + + binary = hex_decode_locked(buf0_with_leading_0, 2); + + binary += hex_decode_locked(reinterpret_cast(&buf[1]), + length - 1, + false); + } + else + binary = hex_decode_locked(reinterpret_cast(buf), + length, false); + + r.binary_decode(&binary[0], binary.size()); + } + else if(base == Decimal) + { + for(size_t i = 0; i != length; ++i) + { + if(Charset::is_space(buf[i])) + continue; + + if(!Charset::is_digit(buf[i])) + throw Invalid_Argument("BigInt::decode: " + "Invalid character in decimal input"); + + const byte x = Charset::char2digit(buf[i]); + + if(x >= 10) + throw Invalid_Argument("BigInt: Invalid decimal string"); + + r *= 10; + r += x; + } + } + else + throw Invalid_Argument("Unknown BigInt decoding method"); + return r; + } + +} diff --git a/src/lib/math/bigint/big_io.cpp b/src/lib/math/bigint/big_io.cpp new file mode 100644 index 000000000..b561c218f --- /dev/null +++ b/src/lib/math/bigint/big_io.cpp @@ -0,0 +1,55 @@ +/* +* BigInt Input/Output +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Write the BigInt into a stream +*/ +std::ostream& operator<<(std::ostream& stream, const BigInt& n) + { + BigInt::Base base = BigInt::Decimal; + if(stream.flags() & std::ios::hex) + base = BigInt::Hexadecimal; + else if(stream.flags() & std::ios::oct) + throw std::runtime_error("Octal output of BigInt not supported"); + + if(n == 0) + stream.write("0", 1); + else + { + if(n < 0) + stream.write("-", 1); + const std::vector buffer = BigInt::encode(n, base); + size_t skip = 0; + while(skip < buffer.size() && buffer[skip] == '0') + ++skip; + stream.write(reinterpret_cast(&buffer[0]) + skip, + buffer.size() - skip); + } + if(!stream.good()) + throw Stream_IO_Error("BigInt output operator has failed"); + return stream; + } + +/* +* Read the BigInt from a stream +*/ +std::istream& operator>>(std::istream& stream, BigInt& n) + { + std::string str; + std::getline(stream, str); + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("BigInt input operator has failed"); + n = BigInt(str); + return stream; + } + +} diff --git a/src/lib/math/bigint/big_ops2.cpp b/src/lib/math/bigint/big_ops2.cpp new file mode 100644 index 000000000..37b6a5df1 --- /dev/null +++ b/src/lib/math/bigint/big_ops2.cpp @@ -0,0 +1,221 @@ +/* +* BigInt Assignment Operators +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Addition Operator +*/ +BigInt& BigInt::operator+=(const BigInt& y) + { + const size_t x_sw = sig_words(), y_sw = y.sig_words(); + + const size_t reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(sign() == y.sign()) + bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw); + else + { + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + if(relative_size < 0) + { + secure_vector z(reg_size - 1); + bigint_sub3(&z[0], y.data(), reg_size - 1, data(), x_sw); + std::swap(m_reg, z); + set_sign(y.sign()); + } + else if(relative_size == 0) + { + zeroise(m_reg); + set_sign(Positive); + } + else if(relative_size > 0) + bigint_sub2(mutable_data(), x_sw, y.data(), y_sw); + } + + return (*this); + } + +/* +* Subtraction Operator +*/ +BigInt& BigInt::operator-=(const BigInt& y) + { + const size_t x_sw = sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + const size_t reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(relative_size < 0) + { + if(sign() == y.sign()) + bigint_sub2_rev(mutable_data(), y.data(), y_sw); + else + bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw); + + set_sign(y.reverse_sign()); + } + else if(relative_size == 0) + { + if(sign() == y.sign()) + { + clear(); + set_sign(Positive); + } + else + bigint_shl1(mutable_data(), x_sw, 0, 1); + } + else if(relative_size > 0) + { + if(sign() == y.sign()) + bigint_sub2(mutable_data(), x_sw, y.data(), y_sw); + else + bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw); + } + + return (*this); + } + +/* +* Multiplication Operator +*/ +BigInt& BigInt::operator*=(const BigInt& y) + { + const size_t x_sw = sig_words(), y_sw = y.sig_words(); + set_sign((sign() == y.sign()) ? Positive : Negative); + + if(x_sw == 0 || y_sw == 0) + { + clear(); + set_sign(Positive); + } + else if(x_sw == 1 && y_sw) + { + grow_to(y_sw + 2); + bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0)); + } + else if(y_sw == 1 && x_sw) + { + grow_to(x_sw + 2); + bigint_linmul2(mutable_data(), x_sw, y.word_at(0)); + } + else + { + grow_to(size() + y.size()); + + secure_vector z(data(), data() + x_sw); + secure_vector workspace(size()); + + bigint_mul(mutable_data(), size(), &workspace[0], + &z[0], z.size(), x_sw, + y.data(), y.size(), y_sw); + } + + return (*this); + } + +/* +* Division Operator +*/ +BigInt& BigInt::operator/=(const BigInt& y) + { + if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) + (*this) >>= (y.bits() - 1); + else + (*this) = (*this) / y; + return (*this); + } + +/* +* Modulo Operator +*/ +BigInt& BigInt::operator%=(const BigInt& mod) + { + return (*this = (*this) % mod); + } + +/* +* Modulo Operator +*/ +word BigInt::operator%=(word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + + if(is_power_of_2(mod)) + { + word result = (word_at(0) & (mod - 1)); + clear(); + grow_to(2); + m_reg[0] = result; + return result; + } + + word remainder = 0; + + for(size_t j = sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, word_at(j-1), mod); + clear(); + grow_to(2); + + if(remainder && sign() == BigInt::Negative) + m_reg[0] = mod - remainder; + else + m_reg[0] = remainder; + + set_sign(BigInt::Positive); + + return word_at(0); + } + +/* +* Left Shift Operator +*/ +BigInt& BigInt::operator<<=(size_t shift) + { + if(shift) + { + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS, + words = sig_words(); + + grow_to(words + shift_words + (shift_bits ? 1 : 0)); + bigint_shl1(mutable_data(), words, shift_words, shift_bits); + } + + return (*this); + } + +/* +* Right Shift Operator +*/ +BigInt& BigInt::operator>>=(size_t shift) + { + if(shift) + { + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + bigint_shr1(mutable_data(), sig_words(), shift_words, shift_bits); + + if(is_zero()) + set_sign(Positive); + } + + return (*this); + } + +} diff --git a/src/lib/math/bigint/big_ops3.cpp b/src/lib/math/bigint/big_ops3.cpp new file mode 100644 index 000000000..cad730197 --- /dev/null +++ b/src/lib/math/bigint/big_ops3.cpp @@ -0,0 +1,191 @@ +/* +* BigInt Binary Operators +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Addition Operator +*/ +BigInt operator+(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); + + if((x.sign() == y.sign())) + bigint_add3(z.mutable_data(), x.data(), x_sw, y.data(), y_sw); + else + { + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + + if(relative_size < 0) + { + bigint_sub3(z.mutable_data(), y.data(), y_sw, x.data(), x_sw); + z.set_sign(y.sign()); + } + else if(relative_size == 0) + z.set_sign(BigInt::Positive); + else if(relative_size > 0) + bigint_sub3(z.mutable_data(), x.data(), x_sw, y.data(), y_sw); + } + + return z; + } + +/* +* Subtraction Operator +*/ +BigInt operator-(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + + BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); + + if(relative_size < 0) + { + if(x.sign() == y.sign()) + bigint_sub3(z.mutable_data(), y.data(), y_sw, x.data(), x_sw); + else + bigint_add3(z.mutable_data(), x.data(), x_sw, y.data(), y_sw); + z.set_sign(y.reverse_sign()); + } + else if(relative_size == 0) + { + if(x.sign() != y.sign()) + bigint_shl2(z.mutable_data(), x.data(), x_sw, 0, 1); + } + else if(relative_size > 0) + { + if(x.sign() == y.sign()) + bigint_sub3(z.mutable_data(), x.data(), x_sw, y.data(), y_sw); + else + bigint_add3(z.mutable_data(), x.data(), x_sw, y.data(), y_sw); + z.set_sign(x.sign()); + } + return z; + } + +/* +* Multiplication Operator +*/ +BigInt operator*(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + BigInt z(BigInt::Positive, x.size() + y.size()); + + if(x_sw == 1 && y_sw) + bigint_linmul3(z.mutable_data(), y.data(), y_sw, x.word_at(0)); + else if(y_sw == 1 && x_sw) + bigint_linmul3(z.mutable_data(), x.data(), x_sw, y.word_at(0)); + else if(x_sw && y_sw) + { + secure_vector workspace(z.size()); + bigint_mul(z.mutable_data(), z.size(), &workspace[0], + x.data(), x.size(), x_sw, + y.data(), y.size(), y_sw); + } + + if(x_sw && y_sw && x.sign() != y.sign()) + z.flip_sign(); + return z; + } + +/* +* Division Operator +*/ +BigInt operator/(const BigInt& x, const BigInt& y) + { + BigInt q, r; + divide(x, y, q, r); + return q; + } + +/* +* Modulo Operator +*/ +BigInt operator%(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative()) + throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); + if(n.is_positive() && mod.is_positive() && n < mod) + return n; + + BigInt q, r; + divide(n, mod, q, r); + return r; + } + +/* +* Modulo Operator +*/ +word operator%(const BigInt& n, word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + + if(is_power_of_2(mod)) + return (n.word_at(0) & (mod - 1)); + + word remainder = 0; + + for(size_t j = n.sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, n.word_at(j-1), mod); + + if(remainder && n.sign() == BigInt::Negative) + return mod - remainder; + return remainder; + } + +/* +* Left Shift Operator +*/ +BigInt operator<<(const BigInt& x, size_t shift) + { + if(shift == 0) + return x; + + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + const size_t x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); + bigint_shl2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +/* +* Right Shift Operator +*/ +BigInt operator>>(const BigInt& x, size_t shift) + { + if(shift == 0) + return x; + if(x.bits() <= shift) + return 0; + + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS, + x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw - shift_words); + bigint_shr2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +} diff --git a/src/lib/math/bigint/big_rand.cpp b/src/lib/math/bigint/big_rand.cpp new file mode 100644 index 000000000..78b9ee244 --- /dev/null +++ b/src/lib/math/bigint/big_rand.cpp @@ -0,0 +1,48 @@ +/* +* BigInt Random Generation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Randomize this number +*/ +void BigInt::randomize(RandomNumberGenerator& rng, + size_t bitsize) + { + set_sign(Positive); + + if(bitsize == 0) + clear(); + else + { + secure_vector array = rng.random_vec((bitsize + 7) / 8); + + if(bitsize % 8) + array[0] &= 0xFF >> (8 - (bitsize % 8)); + array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0); + binary_decode(&array[0], array.size()); + } + } + +/* +* Generate a random integer within given range +*/ +BigInt BigInt::random_integer(RandomNumberGenerator& rng, + const BigInt& min, const BigInt& max) + { + BigInt range = max - min; + + if(range <= 0) + throw Invalid_Argument("random_integer: invalid min/max values"); + + return (min + (BigInt(rng, range.bits() + 2) % range)); + } + +} diff --git a/src/lib/math/bigint/bigint.cpp b/src/lib/math/bigint/bigint.cpp new file mode 100644 index 000000000..45c351256 --- /dev/null +++ b/src/lib/math/bigint/bigint.cpp @@ -0,0 +1,350 @@ +/* +* BigInt Base +* (C) 1999-2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Construct a BigInt from a regular number +*/ +BigInt::BigInt(u64bit n) + { + set_sign(Positive); + + if(n == 0) + return; + + const size_t limbs_needed = sizeof(u64bit) / sizeof(word); + + m_reg.resize(4*limbs_needed); + for(size_t i = 0; i != limbs_needed; ++i) + m_reg[i] = ((n >> (i*MP_WORD_BITS)) & MP_WORD_MASK); + } + +/* +* Construct a BigInt of the specified size +*/ +BigInt::BigInt(Sign s, size_t size) + { + m_reg.resize(round_up(size, 8)); + m_signedness = s; + } + +/* +* Copy constructor +*/ +BigInt::BigInt(const BigInt& other) + { + m_reg = other.m_reg; + m_signedness = other.m_signedness; + } + +/* +* Construct a BigInt from a string +*/ +BigInt::BigInt(const std::string& str) + { + Base base = Decimal; + size_t markers = 0; + bool negative = false; + + if(str.length() > 0 && str[0] == '-') + { + markers += 1; + negative = true; + } + + if(str.length() > markers + 2 && str[markers ] == '0' && + str[markers + 1] == 'x') + { + markers += 2; + base = Hexadecimal; + } + + *this = decode(reinterpret_cast(str.data()) + markers, + str.length() - markers, base); + + if(negative) set_sign(Negative); + else set_sign(Positive); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(const byte input[], size_t length, Base base) + { + set_sign(Positive); + *this = decode(input, length, base); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(RandomNumberGenerator& rng, size_t bits) + { + set_sign(Positive); + randomize(rng, bits); + } + +/* +* Grow the internal storage +*/ +void BigInt::grow_to(size_t n) + { + if(n > size()) + m_reg.resize(round_up(n, 8)); + } + +/* +* Comparison Function +*/ +s32bit BigInt::cmp(const BigInt& other, bool check_signs) const + { + if(check_signs) + { + if(other.is_positive() && this->is_negative()) + return -1; + + if(other.is_negative() && this->is_positive()) + return 1; + + if(other.is_negative() && this->is_negative()) + return (-bigint_cmp(this->data(), this->sig_words(), + other.data(), other.sig_words())); + } + + return bigint_cmp(this->data(), this->sig_words(), + other.data(), other.sig_words()); + } + +/* +* Return byte n of this number +*/ +byte BigInt::byte_at(size_t n) const + { + const size_t WORD_BYTES = sizeof(word); + size_t word_num = n / WORD_BYTES, byte_num = n % WORD_BYTES; + if(word_num >= size()) + return 0; + else + return get_byte(WORD_BYTES - byte_num - 1, m_reg[word_num]); + } + +/* +* Return bit n of this number +*/ +bool BigInt::get_bit(size_t n) const + { + return ((word_at(n / MP_WORD_BITS) >> (n % MP_WORD_BITS)) & 1); + } + +/* +* Return bits {offset...offset+length} +*/ +u32bit BigInt::get_substring(size_t offset, size_t length) const + { + if(length > 32) + throw Invalid_Argument("BigInt::get_substring: Substring size too big"); + + u64bit piece = 0; + for(size_t i = 0; i != 8; ++i) + { + const byte part = byte_at((offset / 8) + (7-i)); + piece = (piece << 8) | part; + } + + const u64bit mask = (static_cast(1) << length) - 1; + const size_t shift = (offset % 8); + + return static_cast((piece >> shift) & mask); + } + +/* +* Convert this number to a u32bit, if possible +*/ +u32bit BigInt::to_u32bit() const + { + if(is_negative()) + throw Encoding_Error("BigInt::to_u32bit: Number is negative"); + if(bits() >= 32) + throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); + + u32bit out = 0; + for(u32bit j = 0; j != 4; ++j) + out = (out << 8) | byte_at(3-j); + return out; + } + +/* +* Set bit number n +*/ +void BigInt::set_bit(size_t n) + { + const size_t which = n / MP_WORD_BITS; + const word mask = static_cast(1) << (n % MP_WORD_BITS); + if(which >= size()) grow_to(which + 1); + m_reg[which] |= mask; + } + +/* +* Clear bit number n +*/ +void BigInt::clear_bit(size_t n) + { + const size_t which = n / MP_WORD_BITS; + const word mask = static_cast(1) << (n % MP_WORD_BITS); + if(which < size()) + m_reg[which] &= ~mask; + } + +/* +* Clear all but the lowest n bits +*/ +void BigInt::mask_bits(size_t n) + { + if(n == 0) { clear(); return; } + if(n >= bits()) return; + + const size_t top_word = n / MP_WORD_BITS; + const word mask = (static_cast(1) << (n % MP_WORD_BITS)) - 1; + + if(top_word < size()) + clear_mem(&m_reg[top_word+1], size() - (top_word + 1)); + + m_reg[top_word] &= mask; + } + +/* +* Count how many bytes are being used +*/ +size_t BigInt::bytes() const + { + return (bits() + 7) / 8; + } + +/* +* Count how many bits are being used +*/ +size_t BigInt::bits() const + { + const size_t words = sig_words(); + + if(words == 0) + return 0; + + size_t full_words = words - 1, top_bits = MP_WORD_BITS; + word top_word = word_at(full_words), mask = MP_WORD_TOP_BIT; + + while(top_bits && ((top_word & mask) == 0)) + { mask >>= 1; top_bits--; } + + return (full_words * MP_WORD_BITS + top_bits); + } + +/* +* Calcluate the size in a certain base +*/ +size_t BigInt::encoded_size(Base base) const + { + static const double LOG_2_BASE_10 = 0.30102999566; + + if(base == Binary) + return bytes(); + else if(base == Hexadecimal) + return 2*bytes(); + else if(base == Decimal) + return static_cast((bits() * LOG_2_BASE_10) + 1); + else + throw Invalid_Argument("Unknown base for BigInt encoding"); + } + +/* +* Set the sign +*/ +void BigInt::set_sign(Sign s) + { + if(is_zero()) + m_signedness = Positive; + else + m_signedness = s; + } + +/* +* Reverse the value of the sign flag +*/ +void BigInt::flip_sign() + { + set_sign(reverse_sign()); + } + +/* +* Return the opposite value of the current sign +*/ +BigInt::Sign BigInt::reverse_sign() const + { + if(sign() == Positive) + return Negative; + return Positive; + } + +/* +* Return the negation of this number +*/ +BigInt BigInt::operator-() const + { + BigInt x = (*this); + x.flip_sign(); + return x; + } + +/* +* Return the absolute value of this number +*/ +BigInt BigInt::abs() const + { + BigInt x = (*this); + x.set_sign(Positive); + return x; + } + +/* +* Encode this number into bytes +*/ +void BigInt::binary_encode(byte output[]) const + { + const size_t sig_bytes = bytes(); + for(size_t i = 0; i != sig_bytes; ++i) + output[sig_bytes-i-1] = byte_at(i); + } + +/* +* Set this number to the value in buf +*/ +void BigInt::binary_decode(const byte buf[], size_t length) + { + const size_t WORD_BYTES = sizeof(word); + + clear(); + m_reg.resize(round_up((length / WORD_BYTES) + 1, 8)); + + for(size_t i = 0; i != length / WORD_BYTES; ++i) + { + const size_t top = length - WORD_BYTES*i; + for(size_t j = WORD_BYTES; j > 0; --j) + m_reg[i] = (m_reg[i] << 8) | buf[top - j]; + } + + for(size_t i = 0; i != length % WORD_BYTES; ++i) + m_reg[length / WORD_BYTES] = (m_reg[length / WORD_BYTES] << 8) | buf[i]; + } + +} diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h new file mode 100644 index 000000000..08b7d53fc --- /dev/null +++ b/src/lib/math/bigint/bigint.h @@ -0,0 +1,570 @@ +/* +* BigInt +* (C) 1999-2008,2012 Jack Lloyd +* 2007 FlexSecure +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BIGINT_H__ +#define BOTAN_BIGINT_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Arbitrary precision integer +*/ +class BOTAN_DLL BigInt + { + public: + /** + * Base enumerator for encoding and decoding + */ + enum Base { Decimal = 10, Hexadecimal = 16, Binary = 256 }; + + /** + * Sign symbol definitions for positive and negative numbers + */ + enum Sign { Negative = 0, Positive = 1 }; + + /** + * DivideByZero Exception + */ + struct BOTAN_DLL DivideByZero : public Exception + { DivideByZero() : Exception("BigInt divide by zero") {} }; + + /** + * Create empty BigInt + */ + BigInt() { m_signedness = Positive; } + + /** + * Create BigInt from 64 bit integer + * @param n initial value of this BigInt + */ + BigInt(u64bit n); + + /** + * Copy Constructor + * @param other the BigInt to copy + */ + BigInt(const BigInt& other); + + /** + * Create BigInt from a string. If the string starts with 0x the + * rest of the string will be interpreted as hexadecimal digits. + * Otherwise, it will be interpreted as a decimal number. + * + * @param str the string to parse for an integer value + */ + BigInt(const std::string& str); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + * @param base is the number base of the integer in buf + */ + BigInt(const byte buf[], size_t length, Base base = Binary); + + /** + * Create a random BigInt of the specified size + * @param rng random number generator + * @param bits size in bits + */ + BigInt(RandomNumberGenerator& rng, size_t bits); + + /** + * Create BigInt of specified size, all zeros + * @param sign the sign + * @param n size of the internal register in words + */ + BigInt(Sign sign, size_t n); + + /** + * Move constructor + */ + BigInt(BigInt&& other) + { + this->swap(other); + } + + /** + * Move assignment + */ + BigInt& operator=(BigInt&& other) + { + if(this != &other) + this->swap(other); + + return (*this); + } + + /** + * Copy assignment + */ + BigInt& operator=(const BigInt&) = default; + + /** + * Swap this value with another + * @param other BigInt to swap values with + */ + void swap(BigInt& other) + { + m_reg.swap(other.m_reg); + std::swap(m_signedness, other.m_signedness); + } + + /** + * += operator + * @param y the BigInt to add to this + */ + BigInt& operator+=(const BigInt& y); + + /** + * -= operator + * @param y the BigInt to subtract from this + */ + BigInt& operator-=(const BigInt& y); + + /** + * *= operator + * @param y the BigInt to multiply with this + */ + BigInt& operator*=(const BigInt& y); + + /** + * /= operator + * @param y the BigInt to divide this by + */ + BigInt& operator/=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus to reduce this by + */ + BigInt& operator%=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus (word) to reduce this by + */ + word operator%=(word y); + + /** + * Left shift operator + * @param shift the number of bits to shift this left by + */ + BigInt& operator<<=(size_t shift); + + /** + * Right shift operator + * @param shift the number of bits to shift this right by + */ + BigInt& operator>>=(size_t shift); + + /** + * Increment operator + */ + BigInt& operator++() { return (*this += 1); } + + /** + * Decrement operator + */ + BigInt& operator--() { return (*this -= 1); } + + /** + * Postfix increment operator + */ + BigInt operator++(int) { BigInt x = (*this); ++(*this); return x; } + + /** + * Postfix decrement operator + */ + BigInt operator--(int) { BigInt x = (*this); --(*this); return x; } + + /** + * Unary negation operator + * @return negative this + */ + BigInt operator-() const; + + /** + * ! operator + * @return true iff this is zero, otherwise false + */ + bool operator !() const { return (!is_nonzero()); } + + /** + * Zeroize the BigInt. The size of the underlying register is not + * modified. + */ + void clear() { zeroise(m_reg); } + + /** + * Compare this to another BigInt + * @param n the BigInt value to compare with + * @param check_signs include sign in comparison? + * @result if (thisn) return 1, if both + * values are identical return 0 [like Perl's <=> operator] + */ + s32bit cmp(const BigInt& n, bool check_signs = true) const; + + /** + * Test if the integer has an even value + * @result true if the integer is even, false otherwise + */ + bool is_even() const { return (get_bit(0) == 0); } + + /** + * Test if the integer has an odd value + * @result true if the integer is odd, false otherwise + */ + bool is_odd() const { return (get_bit(0) == 1); } + + /** + * Test if the integer is not zero + * @result true if the integer is non-zero, false otherwise + */ + bool is_nonzero() const { return (!is_zero()); } + + /** + * Test if the integer is zero + * @result true if the integer is zero, false otherwise + */ + bool is_zero() const + { + const size_t sw = sig_words(); + + for(size_t i = 0; i != sw; ++i) + if(m_reg[i]) + return false; + return true; + } + + /** + * Set bit at specified position + * @param n bit position to set + */ + void set_bit(size_t n); + + /** + * Clear bit at specified position + * @param n bit position to clear + */ + void clear_bit(size_t n); + + /** + * Clear all but the lowest n bits + * @param n amount of bits to keep + */ + void mask_bits(size_t n); + + /** + * Return bit value at specified position + * @param n the bit offset to test + * @result true, if the bit at position n is set, false otherwise + */ + bool get_bit(size_t n) const; + + /** + * Return (a maximum of) 32 bits of the complete value + * @param offset the offset to start extracting + * @param length amount of bits to extract (starting at offset) + * @result the integer extracted from the register starting at + * offset with specified length + */ + u32bit get_substring(size_t offset, size_t length) const; + + /** + * Convert this value into a u32bit, if it is in the range + * [0 ... 2**32-1], or otherwise throw an exception. + * @result the value as a u32bit if conversion is possible + */ + u32bit to_u32bit() const; + + /** + * @param n the offset to get a byte from + * @result byte at offset n + */ + byte byte_at(size_t n) const; + + /** + * Return the word at a specified position of the internal register + * @param n position in the register + * @return value at position n + */ + word word_at(size_t n) const + { return ((n < size()) ? m_reg[n] : 0); } + + /** + * Tests if the sign of the integer is negative + * @result true, iff the integer has a negative sign + */ + bool is_negative() const { return (sign() == Negative); } + + /** + * Tests if the sign of the integer is positive + * @result true, iff the integer has a positive sign + */ + bool is_positive() const { return (sign() == Positive); } + + /** + * Return the sign of the integer + * @result the sign of the integer + */ + Sign sign() const { return (m_signedness); } + + /** + * @result the opposite sign of the represented integer value + */ + Sign reverse_sign() const; + + /** + * Flip the sign of this BigInt + */ + void flip_sign(); + + /** + * Set sign of the integer + * @param sign new Sign to set + */ + void set_sign(Sign sign); + + /** + * @result absolute (positive) value of this + */ + BigInt abs() const; + + /** + * Give size of internal register + * @result size of internal register in words + */ + size_t size() const { return m_reg.size(); } + + /** + * Return how many words we need to hold this value + * @result significant words of the represented integer value + */ + size_t sig_words() const + { + const word* x = &m_reg[0]; + size_t sig = m_reg.size(); + + while(sig && (x[sig-1] == 0)) + sig--; + return sig; + } + + /** + * Give byte length of the integer + * @result byte length of the represented integer value + */ + size_t bytes() const; + + /** + * Get the bit length of the integer + * @result bit length of the represented integer value + */ + size_t bits() const; + + /** + * Return a mutable pointer to the register + * @result a pointer to the start of the internal register + */ + word* mutable_data() { return &m_reg[0]; } + + /** + * Return a const pointer to the register + * @result a pointer to the start of the internal register + */ + const word* data() const { return &m_reg[0]; } + + /** + * Increase internal register buffer to at least n words + * @param n new size of register + */ + void grow_to(size_t n); + + /** + * Fill BigInt with a random number with size of bitsize + * @param rng the random number generator to use + * @param bitsize number of bits the created random value should have + */ + void randomize(RandomNumberGenerator& rng, size_t bitsize = 0); + + /** + * Store BigInt-value in a given byte array + * @param buf destination byte array for the integer value + */ + void binary_encode(byte buf[]) const; + + /** + * Read integer value from a byte array with given size + * @param buf byte array buffer containing the integer + * @param length size of buf + */ + void binary_decode(const byte buf[], size_t length); + + /** + * Read integer value from a byte array (secure_vector) + * @param buf the array to load from + */ + void binary_decode(const secure_vector& buf) + { + binary_decode(&buf[0], buf.size()); + } + + /** + * @param base the base to measure the size for + * @return size of this integer in base base + */ + size_t encoded_size(Base base = Binary) const; + + /** + * @param rng a random number generator + * @param min the minimum value + * @param max the maximum value + * @return random integer between min and max + */ + static BigInt random_integer(RandomNumberGenerator& rng, + const BigInt& min, + const BigInt& max); + + /** + * Create a power of two + * @param n the power of two to create + * @return bigint representing 2^n + */ + static BigInt power_of_2(size_t n) + { + BigInt b; + b.set_bit(n); + return b; + } + + /** + * Encode the integer value from a BigInt to a std::vector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result secure_vector of bytes containing the integer with given base + */ + static std::vector encode(const BigInt& n, Base base = Binary); + + /** + * Encode the integer value from a BigInt to a secure_vector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result secure_vector of bytes containing the integer with given base + */ + static secure_vector encode_locked(const BigInt& n, + Base base = Binary); + + /** + * Encode the integer value from a BigInt to a byte array + * @param buf destination byte array for the encoded integer + * value with given base + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + */ + static void encode(byte buf[], const BigInt& n, Base base = Binary); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param length size of buf + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const byte buf[], size_t length, + Base base = Binary); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const secure_vector& buf, + Base base = Binary) + { + return BigInt::decode(&buf[0], buf.size(), base); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const std::vector& buf, + Base base = Binary) + { + return BigInt::decode(&buf[0], buf.size(), base); + } + + /** + * Encode a BigInt to a byte array according to IEEE 1363 + * @param n the BigInt to encode + * @param bytes the length of the resulting secure_vector + * @result a secure_vector containing the encoded BigInt + */ + static secure_vector encode_1363(const BigInt& n, size_t bytes); + + private: + secure_vector m_reg; + Sign m_signedness; + }; + +/* +* Arithmetic Operators +*/ +BigInt BOTAN_DLL operator+(const BigInt& x, const BigInt& y); +BigInt BOTAN_DLL operator-(const BigInt& x, const BigInt& y); +BigInt BOTAN_DLL operator*(const BigInt& x, const BigInt& y); +BigInt BOTAN_DLL operator/(const BigInt& x, const BigInt& d); +BigInt BOTAN_DLL operator%(const BigInt& x, const BigInt& m); +word BOTAN_DLL operator%(const BigInt& x, word m); +BigInt BOTAN_DLL operator<<(const BigInt& x, size_t n); +BigInt BOTAN_DLL operator>>(const BigInt& x, size_t n); + +/* +* Comparison Operators +*/ +inline bool operator==(const BigInt& a, const BigInt& b) + { return (a.cmp(b) == 0); } +inline bool operator!=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) != 0); } +inline bool operator<=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) <= 0); } +inline bool operator>=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) >= 0); } +inline bool operator<(const BigInt& a, const BigInt& b) + { return (a.cmp(b) < 0); } +inline bool operator>(const BigInt& a, const BigInt& b) + { return (a.cmp(b) > 0); } + +/* +* I/O Operators +*/ +BOTAN_DLL std::ostream& operator<<(std::ostream&, const BigInt&); +BOTAN_DLL std::istream& operator>>(std::istream&, BigInt&); + +} + +namespace std { + +template<> +inline void swap(Botan::BigInt& x, Botan::BigInt& y) + { + x.swap(y); + } + +} + +#endif diff --git a/src/lib/math/bigint/divide.cpp b/src/lib/math/bigint/divide.cpp new file mode 100644 index 000000000..8b21bce13 --- /dev/null +++ b/src/lib/math/bigint/divide.cpp @@ -0,0 +1,140 @@ +/* +* Division Algorithm +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Handle signed operands, if necessary +*/ +void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) + { + if(x.sign() == BigInt::Negative) + { + q.flip_sign(); + if(r.is_nonzero()) { --q; r = y.abs() - r; } + } + if(y.sign() == BigInt::Negative) + q.flip_sign(); + } + +bool division_check(word q, word y2, word y1, + word x3, word x2, word x1) + { + // Compute (y3,y2,y1) = (y2,y1) * q + + word y3 = 0; + y1 = word_madd2(q, y1, &y3); + y2 = word_madd2(q, y2, &y3); + + // Return (y3,y2,y1) >? (x3,x2,x1) + + if(y3 > x3) return true; + if(y3 < x3) return false; + + if(y2 > x2) return true; + if(y2 < x2) return false; + + if(y1 > x1) return true; + if(y1 < x1) return false; + + return false; + } + +} + +/* +* Solve x = q * y + r +*/ +void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r) + { + if(y_arg.is_zero()) + throw BigInt::DivideByZero(); + + BigInt y = y_arg; + const size_t y_words = y.sig_words(); + + r = x; + q = 0; + + r.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + + s32bit compare = r.cmp(y); + + if(compare == 0) + { + q = 1; + r = 0; + } + else if(compare > 0) + { + size_t shifts = 0; + word y_top = y.word_at(y.sig_words()-1); + while(y_top < MP_WORD_TOP_BIT) { y_top <<= 1; ++shifts; } + y <<= shifts; + r <<= shifts; + + const size_t n = r.sig_words() - 1, t = y_words - 1; + + if(n < t) + throw Internal_Error("BigInt division word sizes"); + + q.grow_to(n - t + 1); + + word* q_words = q.mutable_data(); + + if(n <= t) + { + while(r > y) { r -= y; ++q; } + r >>= shifts; + sign_fixup(x, y_arg, q, r); + return; + } + + BigInt temp = y << (MP_WORD_BITS * (n-t)); + + while(r >= temp) { r -= temp; q_words[n-t] += 1; } + + for(size_t j = n; j != t; --j) + { + const word x_j0 = r.word_at(j); + const word x_j1 = r.word_at(j-1); + const word y_t = y.word_at(t); + + if(x_j0 == y_t) + q_words[j-t-1] = MP_WORD_MAX; + else + q_words[j-t-1] = bigint_divop(x_j0, x_j1, y_t); + + while(division_check(q_words[j-t-1], + y_t, y.word_at(t-1), + x_j0, x_j1, r.word_at(j-2))) + { + q_words[j-t-1] -= 1; + } + + r -= (q_words[j-t-1] * y) << (MP_WORD_BITS * (j-t-1)); + + if(r.is_negative()) + { + r += y << (MP_WORD_BITS * (j-t-1)); + q_words[j-t-1] -= 1; + } + } + r >>= shifts; + } + + sign_fixup(x, y_arg, q, r); + } + +} diff --git a/src/lib/math/bigint/divide.h b/src/lib/math/bigint/divide.h new file mode 100644 index 000000000..36aed7854 --- /dev/null +++ b/src/lib/math/bigint/divide.h @@ -0,0 +1,29 @@ +/* +* Division +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DIVISON_ALGORITHM_H__ +#define BOTAN_DIVISON_ALGORITHM_H__ + +#include + +namespace Botan { + +/** +* BigInt Division +* @param x an integer +* @param y a non-zero integer +* @param q will be set to x / y +* @param r will be set to x % y +*/ +void BOTAN_DLL divide(const BigInt& x, + const BigInt& y, + BigInt& q, + BigInt& r); + +} + +#endif diff --git a/src/lib/math/bigint/info.txt b/src/lib/math/bigint/info.txt new file mode 100644 index 000000000..b5dabb7bc --- /dev/null +++ b/src/lib/math/bigint/info.txt @@ -0,0 +1,25 @@ +load_on auto + +define BIGINT 20131128 + + +bigint.h +divide.h + + + +big_code.cpp +big_io.cpp +big_ops2.cpp +big_ops3.cpp +big_rand.cpp +bigint.cpp +divide.cpp + + + +alloc +mp +hex +rng + diff --git a/src/lib/math/ec_gfp/curve_gfp.h b/src/lib/math/ec_gfp/curve_gfp.h new file mode 100644 index 000000000..267d5f152 --- /dev/null +++ b/src/lib/math/ec_gfp/curve_gfp.h @@ -0,0 +1,161 @@ +/* +* Elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2010-2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GFP_CURVE_H__ +#define BOTAN_GFP_CURVE_H__ + +#include + +namespace Botan { + +/** +* This class represents an elliptic curve over GF(p) +*/ +class BOTAN_DLL CurveGFp + { + public: + + /** + * Create an uninitialized CurveGFp + */ + CurveGFp() {} + + /** + * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) + * @param p prime number of the field + * @param a first coefficient + * @param b second coefficient + */ + CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) : + m_p(p), + m_a(a), + m_b(b), + m_p_words(m_p.sig_words()), + m_p_dash(monty_inverse(m_p.word_at(0))) + { + const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); + + m_r2 = (r * r) % p; + m_a_r = (a * r) % p; + m_b_r = (b * r) % p; + } + + CurveGFp(const CurveGFp&) = default; + + CurveGFp& operator=(const CurveGFp&) = default; + + /** + * @return curve coefficient a + */ + const BigInt& get_a() const { return m_a; } + + /** + * @return curve coefficient b + */ + const BigInt& get_b() const { return m_b; } + + /** + * Get prime modulus of the field of the curve + * @return prime modulus of the field of the curve + */ + const BigInt& get_p() const { return m_p; } + + /** + * @return Montgomery parameter r^2 % p + */ + const BigInt& get_r2() const { return m_r2; } + + /** + * @return a * r mod p + */ + const BigInt& get_a_r() const { return m_a_r; } + + /** + * @return b * r mod p + */ + const BigInt& get_b_r() const { return m_b_r; } + + /** + * @return Montgomery parameter p-dash + */ + word get_p_dash() const { return m_p_dash; } + + /** + * @return p.sig_words() + */ + size_t get_p_words() const { return m_p_words; } + + /** + * swaps the states of *this and other, does not throw + * @param other curve to swap values with + */ + void swap(CurveGFp& other) + { + std::swap(m_p, other.m_p); + + std::swap(m_a, other.m_a); + std::swap(m_b, other.m_b); + + std::swap(m_a_r, other.m_a_r); + std::swap(m_b_r, other.m_b_r); + + std::swap(m_p_words, other.m_p_words); + + std::swap(m_r2, other.m_r2); + std::swap(m_p_dash, other.m_p_dash); + } + + /** + * Equality operator + * @param other curve to compare with + * @return true iff this is the same curve as other + */ + bool operator==(const CurveGFp& other) const + { + return (m_p == other.m_p && + m_a == other.m_a && + m_b == other.m_b); + } + + private: + // Curve parameters + BigInt m_p, m_a, m_b; + + size_t m_p_words; // cache of m_p.sig_words() + + // Montgomery parameters + BigInt m_r2, m_a_r, m_b_r; + word m_p_dash; + }; + +/** +* Equality operator +* @param lhs a curve +* @param rhs a curve +* @return true iff lhs is not the same as rhs +*/ +inline bool operator!=(const CurveGFp& lhs, const CurveGFp& rhs) + { + return !(lhs == rhs); + } + +} + +namespace std { + +template<> inline +void swap(Botan::CurveGFp& curve1, + Botan::CurveGFp& curve2) + { + curve1.swap(curve2); + } + +} // namespace std + +#endif diff --git a/src/lib/math/ec_gfp/info.txt b/src/lib/math/ec_gfp/info.txt new file mode 100644 index 000000000..1772302a8 --- /dev/null +++ b/src/lib/math/ec_gfp/info.txt @@ -0,0 +1,16 @@ +define EC_CURVE_GFP 20131128 + +load_on auto + + +curve_gfp.h +point_gfp.h + + + +point_gfp.cpp + + + +numbertheory + diff --git a/src/lib/math/ec_gfp/point_gfp.cpp b/src/lib/math/ec_gfp/point_gfp.cpp new file mode 100644 index 000000000..9cd5a2aaf --- /dev/null +++ b/src/lib/math/ec_gfp/point_gfp.cpp @@ -0,0 +1,606 @@ +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2008-2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +PointGFp::PointGFp(const CurveGFp& curve) : + curve(curve), ws(2 * (curve.get_p_words() + 2)) + { + coord_x = 0; + coord_y = monty_mult(1, curve.get_r2()); + coord_z = 0; + } + +PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) : + curve(curve), ws(2 * (curve.get_p_words() + 2)) + { + coord_x = monty_mult(x, curve.get_r2()); + coord_y = monty_mult(y, curve.get_r2()); + coord_z = monty_mult(1, curve.get_r2()); + } + +// Montgomery multiplication +void PointGFp::monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const + { + //assert(&z != &x && &z != &y); + + if(x.is_zero() || y.is_zero()) + { + z = 0; + return; + } + + const BigInt& p = curve.get_p(); + const size_t p_size = curve.get_p_words(); + const word p_dash = curve.get_p_dash(); + + const size_t output_size = 2*p_size + 1; + + z.grow_to(output_size); + z.clear(); + + bigint_monty_mul(z.mutable_data(), output_size, + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + p.data(), p_size, p_dash, + &ws[0]); + } + +// Montgomery squaring +void PointGFp::monty_sqr(BigInt& z, const BigInt& x) const + { + //assert(&z != &x); + + if(x.is_zero()) + { + z = 0; + return; + } + + const BigInt& p = curve.get_p(); + const size_t p_size = curve.get_p_words(); + const word p_dash = curve.get_p_dash(); + + const size_t output_size = 2*p_size + 1; + + z.grow_to(output_size); + z.clear(); + + bigint_monty_sqr(z.mutable_data(), output_size, + x.data(), x.size(), x.sig_words(), + p.data(), p_size, p_dash, + &ws[0]); + } + +// Point addition +void PointGFp::add(const PointGFp& rhs, std::vector& ws_bn) + { + if(is_zero()) + { + coord_x = rhs.coord_x; + coord_y = rhs.coord_y; + coord_z = rhs.coord_z; + return; + } + else if(rhs.is_zero()) + return; + + const BigInt& p = curve.get_p(); + + BigInt& rhs_z2 = ws_bn[0]; + BigInt& U1 = ws_bn[1]; + BigInt& S1 = ws_bn[2]; + + BigInt& lhs_z2 = ws_bn[3]; + BigInt& U2 = ws_bn[4]; + BigInt& S2 = ws_bn[5]; + + BigInt& H = ws_bn[6]; + BigInt& r = ws_bn[7]; + + monty_sqr(rhs_z2, rhs.coord_z); + monty_mult(U1, coord_x, rhs_z2); + monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2)); + + monty_sqr(lhs_z2, coord_z); + monty_mult(U2, rhs.coord_x, lhs_z2); + monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2)); + + H = U2; + H -= U1; + if(H.is_negative()) + H += p; + + r = S2; + r -= S1; + if(r.is_negative()) + r += p; + + if(H.is_zero()) + { + if(r.is_zero()) + { + mult2(ws_bn); + return; + } + + *this = PointGFp(curve); // setting myself to zero + return; + } + + monty_sqr(U2, H); + + monty_mult(S2, U2, H); + + U2 = monty_mult(U1, U2); + + monty_sqr(coord_x, r); + coord_x -= S2; + coord_x -= (U2 << 1); + while(coord_x.is_negative()) + coord_x += p; + + U2 -= coord_x; + if(U2.is_negative()) + U2 += p; + + monty_mult(coord_y, r, U2); + coord_y -= monty_mult(S1, S2); + if(coord_y.is_negative()) + coord_y += p; + + monty_mult(coord_z, monty_mult(coord_z, rhs.coord_z), H); + } + +// *this *= 2 +void PointGFp::mult2(std::vector& ws_bn) + { + if(is_zero()) + return; + else if(coord_y.is_zero()) + { + *this = PointGFp(curve); // setting myself to zero + return; + } + + const BigInt& p = curve.get_p(); + + BigInt& y_2 = ws_bn[0]; + BigInt& S = ws_bn[1]; + BigInt& z4 = ws_bn[2]; + BigInt& a_z4 = ws_bn[3]; + BigInt& M = ws_bn[4]; + BigInt& U = ws_bn[5]; + BigInt& x = ws_bn[6]; + BigInt& y = ws_bn[7]; + BigInt& z = ws_bn[8]; + + monty_sqr(y_2, coord_y); + + monty_mult(S, coord_x, y_2); + S <<= 2; // * 4 + while(S >= p) + S -= p; + + monty_sqr(z4, monty_sqr(coord_z)); + monty_mult(a_z4, curve.get_a_r(), z4); + + M = 3 * monty_sqr(coord_x); + M += a_z4; + while(M >= p) + M -= p; + + monty_sqr(x, M); + x -= (S << 1); + while(x.is_negative()) + x += p; + + monty_sqr(U, y_2); + U <<= 3; + while(U >= p) + U -= p; + + S -= x; + while(S.is_negative()) + S += p; + + monty_mult(y, M, S); + y -= U; + if(y.is_negative()) + y += p; + + monty_mult(z, coord_y, coord_z); + z <<= 1; + if(z >= p) + z -= p; + + coord_x = x; + coord_y = y; + coord_z = z; + } + +// arithmetic operators +PointGFp& PointGFp::operator+=(const PointGFp& rhs) + { + std::vector ws(9); + add(rhs, ws); + return *this; + } + +PointGFp& PointGFp::operator-=(const PointGFp& rhs) + { + PointGFp minus_rhs = PointGFp(rhs).negate(); + + if(is_zero()) + *this = minus_rhs; + else + *this += minus_rhs; + + return *this; + } + +PointGFp& PointGFp::operator*=(const BigInt& scalar) + { + *this = scalar * *this; + return *this; + } + +PointGFp multi_exponentiate(const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2) + { + const PointGFp p3 = p1 + p2; + + PointGFp H(p1.curve); // create as zero + size_t bits_left = std::max(z1.bits(), z2.bits()); + + std::vector ws(9); + + while(bits_left) + { + H.mult2(ws); + + const bool z1_b = z1.get_bit(bits_left - 1); + const bool z2_b = z2.get_bit(bits_left - 1); + + if(z1_b == true && z2_b == true) + H.add(p3, ws); + else if(z1_b) + H.add(p1, ws); + else if(z2_b) + H.add(p2, ws); + + --bits_left; + } + + if(z1.is_negative() != z2.is_negative()) + H.negate(); + + return H; + } + +PointGFp operator*(const BigInt& scalar, const PointGFp& point) + { + const CurveGFp& curve = point.get_curve(); + + if(scalar.is_zero()) + return PointGFp(curve); // zero point + + std::vector ws(9); + + if(scalar.abs() <= 2) // special cases for small values + { + byte value = scalar.abs().byte_at(0); + + PointGFp result = point; + + if(value == 2) + result.mult2(ws); + + if(scalar.is_negative()) + result.negate(); + + return result; + } + + const size_t scalar_bits = scalar.bits(); + +#if 0 + + PointGFp x1 = PointGFp(curve); + PointGFp x2 = point; + + size_t bits_left = scalar_bits; + + // Montgomery Ladder + while(bits_left) + { + const bool bit_set = scalar.get_bit(bits_left - 1); + + if(bit_set) + { + x1.add(x2, ws); + x2.mult2(ws); + } + else + { + x2.add(x1, ws); + x1.mult2(ws); + } + + --bits_left; + } + + if(scalar.is_negative()) + x1.negate(); + + return x1; + +#else + const size_t window_size = 4; + + std::vector Ps(1 << window_size); + Ps[0] = PointGFp(curve); + Ps[1] = point; + + for(size_t i = 2; i != Ps.size(); ++i) + { + Ps[i] = Ps[i-1]; + Ps[i].add(point, ws); + } + + PointGFp H(curve); // create as zero + size_t bits_left = scalar_bits; + + while(bits_left >= window_size) + { + for(size_t i = 0; i != window_size; ++i) + H.mult2(ws); + + const u32bit nibble = scalar.get_substring(bits_left - window_size, + window_size); + + H.add(Ps[nibble], ws); + + bits_left -= window_size; + } + + while(bits_left) + { + H.mult2(ws); + if(scalar.get_bit(bits_left-1)) + H.add(point, ws); + + --bits_left; + } + + if(scalar.is_negative()) + H.negate(); + + return H; +#endif + } + +BigInt PointGFp::get_affine_x() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + const BigInt& r2 = curve.get_r2(); + + BigInt z2 = monty_sqr(coord_z); + z2 = inverse_mod(z2, curve.get_p()); + + z2 = monty_mult(z2, r2); + return monty_mult(coord_x, z2); + } + +BigInt PointGFp::get_affine_y() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + const BigInt& r2 = curve.get_r2(); + + BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z)); + z3 = inverse_mod(z3, curve.get_p()); + z3 = monty_mult(z3, r2); + return monty_mult(coord_y, z3); + } + +bool PointGFp::on_the_curve() const + { + /* + Is the point still on the curve?? (If everything is correct, the + point is always on its curve; then the function will return true. + If somehow the state is corrupted, which suggests a fault attack + (or internal computational error), then return false. + */ + + if(is_zero()) + return true; + + BigInt y2 = monty_mult(monty_sqr(coord_y), 1); + BigInt x3 = monty_mult(coord_x, monty_sqr(coord_x)); + + BigInt ax = monty_mult(coord_x, curve.get_a_r()); + + const BigInt& b_r = curve.get_b_r(); + + BigInt z2 = monty_sqr(coord_z); + + if(coord_z == z2) // Is z equal to 1 (in Montgomery form)? + { + if(y2 != monty_mult(x3 + ax + b_r, 1)) + return false; + } + + BigInt z3 = monty_mult(coord_z, z2); + + BigInt ax_z4 = monty_mult(ax, monty_sqr(z2)); + + BigInt b_z6 = monty_mult(b_r, monty_sqr(z3)); + + if(y2 != monty_mult(x3 + ax_z4 + b_z6, 1)) + return false; + + return true; + } + +// swaps the states of *this and other, does not throw! +void PointGFp::swap(PointGFp& other) + { + curve.swap(other.curve); + coord_x.swap(other.coord_x); + coord_y.swap(other.coord_y); + coord_z.swap(other.coord_z); + ws.swap(other.ws); + } + +bool PointGFp::operator==(const PointGFp& other) const + { + if(get_curve() != other.get_curve()) + return false; + + // If this is zero, only equal if other is also zero + if(is_zero()) + return other.is_zero(); + + return (get_affine_x() == other.get_affine_x() && + get_affine_y() == other.get_affine_y()); + } + +// encoding and decoding +secure_vector EC2OSP(const PointGFp& point, byte format) + { + if(point.is_zero()) + return secure_vector(1); // single 0 byte + + const size_t p_bytes = point.get_curve().get_p().bytes(); + + BigInt x = point.get_affine_x(); + BigInt y = point.get_affine_y(); + + secure_vector bX = BigInt::encode_1363(x, p_bytes); + secure_vector bY = BigInt::encode_1363(y, p_bytes); + + if(format == PointGFp::UNCOMPRESSED) + { + secure_vector result; + result.push_back(0x04); + + result += bX; + result += bY; + + return result; + } + else if(format == PointGFp::COMPRESSED) + { + secure_vector result; + result.push_back(0x02 | static_cast(y.get_bit(0))); + + result += bX; + + return result; + } + else if(format == PointGFp::HYBRID) + { + secure_vector result; + result.push_back(0x06 | static_cast(y.get_bit(0))); + + result += bX; + result += bY; + + return result; + } + else + throw Invalid_Argument("illegal point encoding format specification"); + } + +namespace { + +BigInt decompress_point(bool yMod2, + const BigInt& x, + const CurveGFp& curve) + { + BigInt xpow3 = x * x * x; + + BigInt g = curve.get_a() * x; + g += xpow3; + g += curve.get_b(); + g = g % curve.get_p(); + + BigInt z = ressol(g, curve.get_p()); + + if(z < 0) + throw Illegal_Point("error during decompression"); + + if(z.get_bit(0) != yMod2) + z = curve.get_p() - z; + + return z; + } + +} + +PointGFp OS2ECP(const byte data[], size_t data_len, + const CurveGFp& curve) + { + if(data_len <= 1) + return PointGFp(curve); // return zero + + const byte pc = data[0]; + + BigInt x, y; + + if(pc == 2 || pc == 3) + { + //compressed form + x = BigInt::decode(&data[1], data_len - 1); + + const bool y_mod_2 = ((pc & 0x01) == 1); + y = decompress_point(y_mod_2, x, curve); + } + else if(pc == 4) + { + const size_t l = (data_len - 1) / 2; + + // uncompressed form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + } + else if(pc == 6 || pc == 7) + { + const size_t l = (data_len - 1) / 2; + + // hybrid form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + + const bool y_mod_2 = ((pc & 0x01) == 1); + + if(decompress_point(y_mod_2, x, curve) != y) + throw Illegal_Point("OS2ECP: Decoding error in hybrid format"); + } + else + throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc)); + + PointGFp result(curve, x, y); + + if(!result.on_the_curve()) + throw Illegal_Point("OS2ECP: Decoded point was not on the curve"); + + return result; + } + +} diff --git a/src/lib/math/ec_gfp/point_gfp.h b/src/lib/math/ec_gfp/point_gfp.h new file mode 100644 index 000000000..017f66e1c --- /dev/null +++ b/src/lib/math/ec_gfp/point_gfp.h @@ -0,0 +1,300 @@ +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2008-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_POINT_GFP_H__ +#define BOTAN_POINT_GFP_H__ + +#include +#include + +namespace Botan { + +/** +* Exception thrown if you try to convert a zero point to an affine +* coordinate +*/ +struct BOTAN_DLL Illegal_Transformation : public Exception + { + Illegal_Transformation(const std::string& err = + "Requested transformation is not possible") : + Exception(err) {} + }; + +/** +* Exception thrown if some form of illegal point is decoded +*/ +struct BOTAN_DLL Illegal_Point : public Exception + { + Illegal_Point(const std::string& err = "Malformed ECP point detected") : + Exception(err) {} + }; + +/** +* This class represents one point on a curve of GF(p) +*/ +class BOTAN_DLL PointGFp + { + public: + enum Compression_Type { + UNCOMPRESSED = 0, + COMPRESSED = 1, + HYBRID = 2 + }; + + /** + * Construct an uninitialized PointGFp + */ + PointGFp() {} + + /** + * Construct the zero point + * @param curve The base curve + */ + PointGFp(const CurveGFp& curve); + + /** + * Copy constructor + */ + PointGFp(const PointGFp&) = default; + + /** + * Move Constructor + */ + PointGFp(PointGFp&& other) + { + this->swap(other); + } + + /** + * Standard Assignment + */ + PointGFp& operator=(const PointGFp&) = default; + + /** + * Move Assignment + */ + PointGFp& operator=(PointGFp&& other) + { + if(this != &other) + this->swap(other); + return (*this); + } + + /** + * Construct a point from its affine coordinates + * @param curve the base curve + * @param x affine x coordinate + * @param y affine y coordinate + */ + PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y); + + /** + * += Operator + * @param rhs the PointGFp to add to the local value + * @result resulting PointGFp + */ + PointGFp& operator+=(const PointGFp& rhs); + + /** + * -= Operator + * @param rhs the PointGFp to subtract from the local value + * @result resulting PointGFp + */ + PointGFp& operator-=(const PointGFp& rhs); + + /** + * *= Operator + * @param scalar the PointGFp to multiply with *this + * @result resulting PointGFp + */ + PointGFp& operator*=(const BigInt& scalar); + + /** + * Multiplication Operator + * @param scalar the scalar value + * @param point the point value + * @return scalar*point on the curve + */ + friend BOTAN_DLL PointGFp operator*(const BigInt& scalar, const PointGFp& point); + + /** + * Multiexponentiation + * @param p1 a point + * @param z1 a scalar + * @param p2 a point + * @param z2 a scalar + * @result (p1 * z1 + p2 * z2) + */ + friend BOTAN_DLL PointGFp multi_exponentiate( + const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2); + + /** + * Negate this point + * @return *this + */ + PointGFp& negate() + { + if(!is_zero()) + coord_y = curve.get_p() - coord_y; + return *this; + } + + /** + * Return base curve of this point + * @result the curve over GF(p) of this point + */ + const CurveGFp& get_curve() const { return curve; } + + /** + * get affine x coordinate + * @result affine x coordinate + */ + BigInt get_affine_x() const; + + /** + * get affine y coordinate + * @result affine y coordinate + */ + BigInt get_affine_y() const; + + /** + * Is this the point at infinity? + * @result true, if this point is at infinity, false otherwise. + */ + bool is_zero() const + { return (coord_x.is_zero() && coord_z.is_zero()); } + + /** + * Checks whether the point is to be found on the underlying + * curve; used to prevent fault attacks. + * @return if the point is on the curve + */ + bool on_the_curve() const; + + /** + * swaps the states of *this and other, does not throw! + * @param other the object to swap values with + */ + void swap(PointGFp& other); + + /** + * Equality operator + */ + bool operator==(const PointGFp& other) const; + private: + + /** + * Montgomery multiplication/reduction + * @param x first multiplicand + * @param y second multiplicand + * @param workspace temp space + */ + BigInt monty_mult(const BigInt& x, const BigInt& y) const + { + BigInt result; + monty_mult(result, x, y); + return result; + } + + /** + * Montgomery multiplication/reduction + * @warning z cannot alias x or y + * @param z output + * @param x first multiplicand + * @param y second multiplicand + */ + void monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const; + + /** + * Montgomery squaring/reduction + * @param x multiplicand + */ + BigInt monty_sqr(const BigInt& x) const + { + BigInt result; + monty_sqr(result, x); + return result; + } + + /** + * Montgomery squaring/reduction + * @warning z cannot alias x + * @param z output + * @param x multiplicand + */ + void monty_sqr(BigInt& z, const BigInt& x) const; + + /** + * Point addition + * @param workspace temp space, at least 11 elements + */ + void add(const PointGFp& other, std::vector& workspace); + + /** + * Point doubling + * @param workspace temp space, at least 9 elements + */ + void mult2(std::vector& workspace); + + CurveGFp curve; + BigInt coord_x, coord_y, coord_z; + mutable secure_vector ws; // workspace for Montgomery + }; + +// relational operators +inline bool operator!=(const PointGFp& lhs, const PointGFp& rhs) + { + return !(rhs == lhs); + } + +// arithmetic operators +inline PointGFp operator-(const PointGFp& lhs) + { + return PointGFp(lhs).negate(); + } + +inline PointGFp operator+(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp += rhs; + } + +inline PointGFp operator-(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp -= rhs; + } + +inline PointGFp operator*(const PointGFp& point, const BigInt& scalar) + { + return scalar * point; + } + +// encoding and decoding +secure_vector BOTAN_DLL EC2OSP(const PointGFp& point, byte format); + +PointGFp BOTAN_DLL OS2ECP(const byte data[], size_t data_len, + const CurveGFp& curve); + +template +PointGFp OS2ECP(const std::vector& data, const CurveGFp& curve) + { return OS2ECP(&data[0], data.size(), curve); } + +} + +namespace std { + +template<> +inline void swap(Botan::PointGFp& x, Botan::PointGFp& y) + { x.swap(y); } + +} + +#endif diff --git a/src/lib/math/mp/info.txt b/src/lib/math/mp/info.txt new file mode 100644 index 000000000..a47475f7b --- /dev/null +++ b/src/lib/math/mp/info.txt @@ -0,0 +1,23 @@ +define BIGINT_MP 20131128 + + +mp_asm.cpp +mp_comba.cpp +mp_karat.cpp +mp_monty.cpp +mp_mulop.cpp +mp_misc.cpp +mp_shift.cpp + + + +mp_types.h + + + +mp_core.h + + + +mp_x86_64|mp_x86_32|mp_x86_32_msvc|mp_generic + diff --git a/src/lib/math/mp/mp_asm.cpp b/src/lib/math/mp/mp_asm.cpp new file mode 100644 index 000000000..a3caba620 --- /dev/null +++ b/src/lib/math/mp/mp_asm.cpp @@ -0,0 +1,184 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +extern "C" { + +/* +* Two Operand Addition, No Carry +*/ +word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) + { + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add2(x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/* +* Three Operand Addition, No Carry +*/ +word bigint_add3_nc(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) + { return bigint_add3_nc(z, y, y_size, x, x_size); } + + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add3(z + i, x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/* +* Two Operand Addition +*/ +void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) + { + if(bigint_add2_nc(x, x_size, y, y_size)) + x[x_size] += 1; + } + +/* +* Three Operand Addition +*/ +void bigint_add3(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + z[(x_size > y_size ? x_size : y_size)] += + bigint_add3_nc(z, x, x_size, y, y_size); + } + +/* +* Two Operand Subtraction +*/ +word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/* +* Two Operand Subtraction x = y - x +*/ +void bigint_sub2_rev(word x[], const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2_rev(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(y[i], x[i], &borrow); + + if(borrow) + throw Internal_Error("bigint_sub2_rev: x >= y"); + } + +/* +* Three Operand Subtraction +*/ +word bigint_sub3(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub3(z + i, x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/* +* Two Operand Linear Multiply +*/ +void bigint_linmul2(word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul2(x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + x[i] = word_madd2(x[i], y, &carry); + + x[x_size] = carry; + } + +/* +* Three Operand Linear Multiply +*/ +void bigint_linmul3(word z[], const word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul3(z + i, x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + z[i] = word_madd2(x[i], y, &carry); + + z[x_size] = carry; + } + +} + +} diff --git a/src/lib/math/mp/mp_comba.cpp b/src/lib/math/mp/mp_comba.cpp new file mode 100644 index 000000000..99dcda176 --- /dev/null +++ b/src/lib/math/mp/mp_comba.cpp @@ -0,0 +1,920 @@ +/* +* Comba Multiplication and Squaring +* (C) 1999-2007,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +extern "C" { + +/* +* Comba 4x4 Squaring +*/ +void bigint_comba_sqr4(word z[8], const word x[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 4x4 Multiplication +*/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 6x6 Squaring +*/ +void bigint_comba_sqr6(word z[12], const word x[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 6x6 Multiplication +*/ +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 8x8 Squaring +*/ +void bigint_comba_sqr8(word z[16], const word x[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 8x8 Multiplication +*/ +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 16x16 Squaring +*/ +void bigint_comba_sqr16(word z[32], const word x[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); + z[17] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], x[ 9]); + z[18] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); + z[19] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); + word3_muladd(&w1, &w0, &w2, x[10], x[10]); + z[20] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); + z[21] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); + word3_muladd(&w0, &w2, &w1, x[11], x[11]); + z[22] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); + z[23] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); + word3_muladd(&w2, &w1, &w0, x[12], x[12]); + z[24] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); + z[25] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); + word3_muladd(&w1, &w0, &w2, x[13], x[13]); + z[26] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); + z[27] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); + word3_muladd(&w0, &w2, &w1, x[14], x[14]); + z[28] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[15], x[15]); + z[30] = w0; + z[31] = w1; + } + +/* +* Comba 16x16 Multiplication +*/ +void bigint_comba_mul16(word z[32], const word x[16], const word y[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); + z[16] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); + z[17] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); + z[18] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); + z[19] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); + word3_muladd(&w1, &w0, &w2, x[10], y[10]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); + z[20] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); + word3_muladd(&w2, &w1, &w0, x[10], y[11]); + word3_muladd(&w2, &w1, &w0, x[11], y[10]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); + z[21] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); + word3_muladd(&w0, &w2, &w1, x[10], y[12]); + word3_muladd(&w0, &w2, &w1, x[11], y[11]); + word3_muladd(&w0, &w2, &w1, x[12], y[10]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); + z[22] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); + word3_muladd(&w1, &w0, &w2, x[10], y[13]); + word3_muladd(&w1, &w0, &w2, x[11], y[12]); + word3_muladd(&w1, &w0, &w2, x[12], y[11]); + word3_muladd(&w1, &w0, &w2, x[13], y[10]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); + z[23] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); + word3_muladd(&w2, &w1, &w0, x[10], y[14]); + word3_muladd(&w2, &w1, &w0, x[11], y[13]); + word3_muladd(&w2, &w1, &w0, x[12], y[12]); + word3_muladd(&w2, &w1, &w0, x[13], y[11]); + word3_muladd(&w2, &w1, &w0, x[14], y[10]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); + z[24] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[10], y[15]); + word3_muladd(&w0, &w2, &w1, x[11], y[14]); + word3_muladd(&w0, &w2, &w1, x[12], y[13]); + word3_muladd(&w0, &w2, &w1, x[13], y[12]); + word3_muladd(&w0, &w2, &w1, x[14], y[11]); + word3_muladd(&w0, &w2, &w1, x[15], y[10]); + z[25] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[11], y[15]); + word3_muladd(&w1, &w0, &w2, x[12], y[14]); + word3_muladd(&w1, &w0, &w2, x[13], y[13]); + word3_muladd(&w1, &w0, &w2, x[14], y[12]); + word3_muladd(&w1, &w0, &w2, x[15], y[11]); + z[26] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[12], y[15]); + word3_muladd(&w2, &w1, &w0, x[13], y[14]); + word3_muladd(&w2, &w1, &w0, x[14], y[13]); + word3_muladd(&w2, &w1, &w0, x[15], y[12]); + z[27] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[13], y[15]); + word3_muladd(&w0, &w2, &w1, x[14], y[14]); + word3_muladd(&w0, &w2, &w1, x[15], y[13]); + z[28] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[14], y[15]); + word3_muladd(&w1, &w0, &w2, x[15], y[14]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[15], y[15]); + z[30] = w0; + z[31] = w1; + } + +} + +} diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h new file mode 100644 index 000000000..c25cb994f --- /dev/null +++ b/src/lib/math/mp/mp_core.h @@ -0,0 +1,175 @@ +/* +* MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_CORE_OPS_H__ +#define BOTAN_MP_CORE_OPS_H__ + +#include + +namespace Botan { + +/* +* The size of the word type, in bits +*/ +const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS; + +extern "C" { + +/** +* Two operand addition +* @param x the first operand (and output) +* @param x_size size of x +* @param y the second operand +* @param y_size size of y (must be >= x_size) +*/ +void bigint_add2(word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Three operand addition +*/ +void bigint_add3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Two operand addition with carry out +*/ +word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size); + +/** +* Three operand addition with carry out +*/ +word bigint_add3_nc(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Two operand subtraction +*/ +word bigint_sub2(word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Two operand subtraction, x = y - x; assumes y >= x +*/ +void bigint_sub2_rev(word x[], const word y[], size_t y_size); + +/** +* Three operand subtraction +*/ +word bigint_sub3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/* +* Shift Operations +*/ +void bigint_shl1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shr1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +/* +* Simple O(N^2) Multiplication and Squaring +*/ +void bigint_simple_mul(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +void bigint_simple_sqr(word z[], const word x[], size_t x_size); + +/* +* Linear Multiply +*/ +void bigint_linmul2(word x[], size_t x_size, word y); +void bigint_linmul3(word z[], const word x[], size_t x_size, word y); + +/** +* Montgomery Reduction +* @param z integer to reduce, of size exactly 2*(p_size+1). + Output is in the first p_size+1 words, higher + words are set to zero. +* @param p modulus +* @param p_size size of p +* @param p_dash Montgomery value +* @param workspace array of at least 2*(p_size+1) words +*/ +void bigint_monty_redc(word z[], + const word p[], size_t p_size, + word p_dash, + word workspace[]); + +/* +* Montgomery Multiplication +*/ +void bigint_monty_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/* +* Montgomery Squaring +*/ +void bigint_monty_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/** +* Compare x and y +*/ +s32bit bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Compute ((n1< +mp_madd.h +mp_asmi.h + diff --git a/src/lib/math/mp/mp_generic/mp_asmi.h b/src/lib/math/mp/mp_generic/mp_asmi.h new file mode 100644 index 000000000..018055696 --- /dev/null +++ b/src/lib/math/mp/mp_generic/mp_asmi.h @@ -0,0 +1,207 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H__ +#define BOTAN_MP_ASM_INTERNAL_H__ + +#include + +namespace Botan { + +extern "C" { + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { + word z = x + y; + word c1 = (z < x); + z += *carry; + *carry = c1 | (z < *carry); + return z; + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { + x[0] = word_add(x[0], y[0], &carry); + x[1] = word_add(x[1], y[1], &carry); + x[2] = word_add(x[2], y[2], &carry); + x[3] = word_add(x[3], y[3], &carry); + x[4] = word_add(x[4], y[4], &carry); + x[5] = word_add(x[5], y[5], &carry); + x[6] = word_add(x[6], y[6], &carry); + x[7] = word_add(x[7], y[7], &carry); + return carry; + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], + const word y[8], word carry) + { + z[0] = word_add(x[0], y[0], &carry); + z[1] = word_add(x[1], y[1], &carry); + z[2] = word_add(x[2], y[2], &carry); + z[3] = word_add(x[3], y[3], &carry); + z[4] = word_add(x[4], y[4], &carry); + z[5] = word_add(x[5], y[5], &carry); + z[6] = word_add(x[6], y[6], &carry); + z[7] = word_add(x[7], y[7], &carry); + return carry; + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { + word t0 = x - y; + word c1 = (t0 > x); + word z = t0 - *carry; + *carry = c1 | (z > t0); + return z; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { + x[0] = word_sub(x[0], y[0], &carry); + x[1] = word_sub(x[1], y[1], &carry); + x[2] = word_sub(x[2], y[2], &carry); + x[3] = word_sub(x[3], y[3], &carry); + x[4] = word_sub(x[4], y[4], &carry); + x[5] = word_sub(x[5], y[5], &carry); + x[6] = word_sub(x[6], y[6], &carry); + x[7] = word_sub(x[7], y[7], &carry); + return carry; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { + x[0] = word_sub(y[0], x[0], &carry); + x[1] = word_sub(y[1], x[1], &carry); + x[2] = word_sub(y[2], x[2], &carry); + x[3] = word_sub(y[3], x[3], &carry); + x[4] = word_sub(y[4], x[4], &carry); + x[5] = word_sub(y[5], x[5], &carry); + x[6] = word_sub(y[6], x[6], &carry); + x[7] = word_sub(y[7], x[7], &carry); + return carry; + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], + const word y[8], word carry) + { + z[0] = word_sub(x[0], y[0], &carry); + z[1] = word_sub(x[1], y[1], &carry); + z[2] = word_sub(x[2], y[2], &carry); + z[3] = word_sub(x[3], y[3], &carry); + z[4] = word_sub(x[4], y[4], &carry); + z[5] = word_sub(x[5], y[5], &carry); + z[6] = word_sub(x[6], y[6], &carry); + z[7] = word_sub(x[7], y[7], &carry); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { + x[0] = word_madd2(x[0], y, &carry); + x[1] = word_madd2(x[1], y, &carry); + x[2] = word_madd2(x[2], y, &carry); + x[3] = word_madd2(x[3], y, &carry); + x[4] = word_madd2(x[4], y, &carry); + x[5] = word_madd2(x[5], y, &carry); + x[6] = word_madd2(x[6], y, &carry); + x[7] = word_madd2(x[7], y, &carry); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { + z[0] = word_madd2(x[0], y, &carry); + z[1] = word_madd2(x[1], y, &carry); + z[2] = word_madd2(x[2], y, &carry); + z[3] = word_madd2(x[3], y, &carry); + z[4] = word_madd2(x[4], y, &carry); + z[5] = word_madd2(x[5], y, &carry); + z[6] = word_madd2(x[6], y, &carry); + z[7] = word_madd2(x[7], y, &carry); + return carry; + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { + z[0] = word_madd3(x[0], y, z[0], &carry); + z[1] = word_madd3(x[1], y, z[1], &carry); + z[2] = word_madd3(x[2], y, z[2], &carry); + z[3] = word_madd3(x[3], y, z[3], &carry); + z[4] = word_madd3(x[4], y, z[4], &carry); + z[5] = word_madd3(x[5], y, z[5], &carry); + z[6] = word_madd3(x[6], y, z[6], &carry); + z[7] = word_madd3(x[7], y, z[7], &carry); + return carry; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b) + { + word carry = *w0; + *w0 = word_madd2(a, b, &carry); + *w1 += carry; + *w2 += (*w1 < carry) ? 1 : 0; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b) + { + word carry = 0; + a = word_madd2(a, b, &carry); + b = carry; + + word top = (b >> (BOTAN_MP_WORD_BITS-1)); + b <<= 1; + b |= (a >> (BOTAN_MP_WORD_BITS-1)); + a <<= 1; + + carry = 0; + *w0 = word_add(*w0, a, &carry); + *w1 = word_add(*w1, b, &carry); + *w2 = word_add(*w2, top, &carry); + } + +} + +} + +#endif diff --git a/src/lib/math/mp/mp_generic/mp_madd.h b/src/lib/math/mp/mp_generic/mp_madd.h new file mode 100644 index 000000000..17713f55f --- /dev/null +++ b/src/lib/math/mp/mp_generic/mp_madd.h @@ -0,0 +1,73 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2008,2013 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_WORD_MULADD_H__ +#define BOTAN_MP_WORD_MULADD_H__ + +#include + +namespace Botan { + +extern "C" { + +/* +* Word Multiply/Add +*/ +inline word word_madd2(word a, word b, word* c) + { +#if defined(BOTAN_HAS_MP_DWORD) + const dword s = static_cast(a) * b + *c; + *c = static_cast(s >> BOTAN_MP_WORD_BITS); + return static_cast(s); +#else + static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); + + word hi = 0, lo = 0; + + mul64x64_128(a, b, &lo, &hi); + + lo += *c; + hi += (lo < *c); // carry? + + *c = hi; + return lo; +#endif + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { +#if defined(BOTAN_HAS_MP_DWORD) + const dword s = static_cast(a) * b + c + *d; + *d = static_cast(s >> BOTAN_MP_WORD_BITS); + return static_cast(s); +#else + static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); + + word hi = 0, lo = 0; + + mul64x64_128(a, b, &lo, &hi); + + lo += c; + hi += (lo < c); // carry? + + lo += *d; + hi += (lo < *d); // carry? + + *d = hi; + return lo; +#endif + } + +} + +} + +#endif diff --git a/src/lib/math/mp/mp_karat.cpp b/src/lib/math/mp/mp_karat.cpp new file mode 100644 index 000000000..b549a05c8 --- /dev/null +++ b/src/lib/math/mp/mp_karat.cpp @@ -0,0 +1,303 @@ +/* +* Karatsuba Multiplication/Squaring +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +static const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32; +static const size_t KARATSUBA_SQUARE_THRESHOLD = 32; + +/* +* Karatsuba Multiplication Operation +*/ +void karatsuba_mul(word z[], const word x[], const word y[], size_t N, + word workspace[]) + { + if(N < KARATSUBA_MULTIPLY_THRESHOLD || N % 2) + { + if(N == 6) + return bigint_comba_mul6(z, x, y); + else if(N == 8) + return bigint_comba_mul8(z, x, y); + else if(N == 16) + return bigint_comba_mul16(z, x, y); + else + return bigint_simple_mul(z, x, N, y, N); + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + const word* y0 = y; + const word* y1 = y + N2; + word* z0 = z; + word* z1 = z + N; + + const s32bit cmp0 = bigint_cmp(x0, N2, x1, N2); + const s32bit cmp1 = bigint_cmp(y1, N2, y0, N2); + + clear_mem(workspace, 2*N); + + //if(cmp0 && cmp1) + { + if(cmp0 > 0) + bigint_sub3(z0, x0, N2, x1, N2); + else + bigint_sub3(z0, x1, N2, x0, N2); + + if(cmp1 > 0) + bigint_sub3(z1, y1, N2, y0, N2); + else + bigint_sub3(z1, y0, N2, y1, N2); + + karatsuba_mul(workspace, z0, z1, N2, workspace+N); + } + + karatsuba_mul(z0, x0, y0, N2, workspace+N); + karatsuba_mul(z1, x1, y1, N2, workspace+N); + + const word ws_carry = bigint_add3_nc(workspace + N, z0, N, z1, N); + word z_carry = bigint_add2_nc(z + N2, N, workspace + N, N); + + z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); + bigint_add2_nc(z + N + N2, N2, &z_carry, 1); + + if((cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0)) + bigint_add2(z + N2, 2*N-N2, workspace, N); + else + bigint_sub2(z + N2, 2*N-N2, workspace, N); + } + +/* +* Karatsuba Squaring Operation +*/ +void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[]) + { + if(N < KARATSUBA_SQUARE_THRESHOLD || N % 2) + { + if(N == 6) + return bigint_comba_sqr6(z, x); + else if(N == 8) + return bigint_comba_sqr8(z, x); + else if(N == 16) + return bigint_comba_sqr16(z, x); + else + return bigint_simple_sqr(z, x, N); + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + word* z0 = z; + word* z1 = z + N; + + const s32bit cmp = bigint_cmp(x0, N2, x1, N2); + + clear_mem(workspace, 2*N); + + //if(cmp) + { + if(cmp > 0) + bigint_sub3(z0, x0, N2, x1, N2); + else + bigint_sub3(z0, x1, N2, x0, N2); + + karatsuba_sqr(workspace, z0, N2, workspace+N); + } + + karatsuba_sqr(z0, x0, N2, workspace+N); + karatsuba_sqr(z1, x1, N2, workspace+N); + + const word ws_carry = bigint_add3_nc(workspace + N, z0, N, z1, N); + word z_carry = bigint_add2_nc(z + N2, N, workspace + N, N); + + z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); + bigint_add2_nc(z + N + N2, N2, &z_carry, 1); + + /* + * This is only actually required if cmp is != 0, however + * if cmp==0 then workspace[0:N] == 0 and avoiding the jump + * hides a timing channel. + */ + bigint_sub2(z + N2, 2*N-N2, workspace, N); + } + +/* +* Pick a good size for the Karatsuba multiply +*/ +size_t karatsuba_size(size_t z_size, + size_t x_size, size_t x_sw, + size_t y_size, size_t y_sw) + { + if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) + return 0; + + if(((x_size == x_sw) && (x_size % 2)) || + ((y_size == y_sw) && (y_size % 2))) + return 0; + + const size_t start = (x_sw > y_sw) ? x_sw : y_sw; + const size_t end = (x_size < y_size) ? x_size : y_size; + + if(start == end) + { + if(start % 2) + return 0; + return start; + } + + for(size_t j = start; j <= end; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) + { + if(j % 4 == 2 && + (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + } + + return 0; + } + +/* +* Pick a good size for the Karatsuba squaring +*/ +size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw) + { + if(x_sw == x_size) + { + if(x_sw % 2) + return 0; + return x_sw; + } + + for(size_t j = x_sw; j <= x_size; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + + return 0; + } + +} + +/* +* Multiplication Algorithm Dispatcher +*/ +void bigint_mul(word z[], size_t z_size, word workspace[], + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw) + { + if(x_sw == 1) + { + bigint_linmul3(z, y, y_sw, x[0]); + } + else if(y_sw == 1) + { + bigint_linmul3(z, x, x_sw, y[0]); + } + else if(x_sw <= 4 && x_size >= 4 && + y_sw <= 4 && y_size >= 4 && z_size >= 8) + { + bigint_comba_mul4(z, x, y); + } + else if(x_sw <= 6 && x_size >= 6 && + y_sw <= 6 && y_size >= 6 && z_size >= 12) + { + bigint_comba_mul6(z, x, y); + } + else if(x_sw <= 8 && x_size >= 8 && + y_sw <= 8 && y_size >= 8 && z_size >= 16) + { + bigint_comba_mul8(z, x, y); + } + else if(x_sw <= 16 && x_size >= 16 && + y_sw <= 16 && y_size >= 16 && z_size >= 32) + { + bigint_comba_mul16(z, x, y); + } + else if(x_sw < KARATSUBA_MULTIPLY_THRESHOLD || + y_sw < KARATSUBA_MULTIPLY_THRESHOLD || + !workspace) + { + bigint_simple_mul(z, x, x_sw, y, y_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); + + if(N) + karatsuba_mul(z, x, y, N, workspace); + else + bigint_simple_mul(z, x, x_sw, y, y_sw); + } + } + +/* +* Squaring Algorithm Dispatcher +*/ +void bigint_sqr(word z[], size_t z_size, word workspace[], + const word x[], size_t x_size, size_t x_sw) + { + if(x_sw == 1) + { + bigint_linmul3(z, x, x_sw, x[0]); + } + else if(x_sw <= 4 && x_size >= 4 && z_size >= 8) + { + bigint_comba_sqr4(z, x); + } + else if(x_sw <= 6 && x_size >= 6 && z_size >= 12) + { + bigint_comba_sqr6(z, x); + } + else if(x_sw <= 8 && x_size >= 8 && z_size >= 16) + { + bigint_comba_sqr8(z, x); + } + else if(x_sw <= 16 && x_size >= 16 && z_size >= 32) + { + bigint_comba_sqr16(z, x); + } + else if(x_size < KARATSUBA_SQUARE_THRESHOLD || !workspace) + { + bigint_simple_sqr(z, x, x_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw); + + if(N) + karatsuba_sqr(z, x, N, workspace); + else + bigint_simple_sqr(z, x, x_sw); + } + } + +} diff --git a/src/lib/math/mp/mp_misc.cpp b/src/lib/math/mp/mp_misc.cpp new file mode 100644 index 000000000..0efd5fd19 --- /dev/null +++ b/src/lib/math/mp/mp_misc.cpp @@ -0,0 +1,79 @@ +/* +* MP Misc Functions +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +extern "C" { + +/* +* Compare two MP integers +*/ +s32bit bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); } + + while(x_size > y_size) + { + if(x[x_size-1]) + return 1; + x_size--; + } + + for(size_t i = x_size; i > 0; --i) + { + if(x[i-1] > y[i-1]) + return 1; + if(x[i-1] < y[i-1]) + return -1; + } + + return 0; + } + +/* +* Do a 2-word/1-word Division +*/ +word bigint_divop(word n1, word n0, word d) + { + word high = n1 % d, quotient = 0; + + for(size_t i = 0; i != MP_WORD_BITS; ++i) + { + word high_top_bit = (high & MP_WORD_TOP_BIT); + + high <<= 1; + high |= (n0 >> (MP_WORD_BITS-1-i)) & 1; + quotient <<= 1; + + if(high_top_bit || high >= d) + { + high -= d; + quotient |= 1; + } + } + + return quotient; + } + +/* +* Do a 2-word/1-word Modulo +*/ +word bigint_modop(word n1, word n0, word d) + { + word z = bigint_divop(n1, n0, d); + word dummy = 0; + z = word_madd2(z, d, &dummy); + return (n0-z); + } + +} + +} diff --git a/src/lib/math/mp/mp_monty.cpp b/src/lib/math/mp/mp_monty.cpp new file mode 100644 index 000000000..095457dbe --- /dev/null +++ b/src/lib/math/mp/mp_monty.cpp @@ -0,0 +1,101 @@ +/* +* Montgomery Reduction +* (C) 1999-2011 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +extern "C" { + +/* +* Montgomery Reduction Algorithm +*/ +void bigint_monty_redc(word z[], + const word p[], size_t p_size, + word p_dash, word ws[]) + { + const size_t z_size = 2*(p_size+1); + + const size_t blocks_of_8 = p_size - (p_size % 8); + + for(size_t i = 0; i != p_size; ++i) + { + word* z_i = z + i; + + const word y = z_i[0] * p_dash; + + /* + bigint_linmul3(ws, p, p_size, y); + bigint_add2(z_i, z_size - i, ws, p_size+1); + */ + + word carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + carry = word8_madd3(z_i + j, p + j, y, carry); + + for(size_t j = blocks_of_8; j != p_size; ++j) + z_i[j] = word_madd3(p[j], y, z_i[j], &carry); + + word z_sum = z_i[p_size] + carry; + carry = (z_sum < z_i[p_size]); + z_i[p_size] = z_sum; + + for(size_t j = p_size + 1; carry && j != z_size - i; ++j) + { + ++z_i[j]; + carry = !z_i[j]; + } + } + + word borrow = 0; + for(size_t i = 0; i != p_size; ++i) + ws[i] = word_sub(z[p_size + i], p[i], &borrow); + + ws[p_size] = word_sub(z[p_size+p_size], 0, &borrow); + + copy_mem(ws + p_size + 1, z + p_size, p_size + 1); + + copy_mem(z, ws + borrow*(p_size+1), p_size + 1); + clear_mem(z + p_size + 1, z_size - p_size - 1); + } + +void bigint_monty_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + bigint_mul(&z[0], z_size, &ws[0], + &x[0], x_size, x_sw, + &y[0], y_size, y_sw); + + bigint_monty_redc(&z[0], + &p[0], p_size, p_dash, + &ws[0]); + } + +void bigint_monty_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + bigint_sqr(&z[0], z_size, &ws[0], + &x[0], x_size, x_sw); + + bigint_monty_redc(&z[0], + &p[0], p_size, p_dash, + &ws[0]); + } + +} + +} diff --git a/src/lib/math/mp/mp_mulop.cpp b/src/lib/math/mp/mp_mulop.cpp new file mode 100644 index 000000000..0c79cc2ef --- /dev/null +++ b/src/lib/math/mp/mp_mulop.cpp @@ -0,0 +1,77 @@ +/* +* Simple O(N^2) Multiplication and Squaring +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +extern "C" { + +/* +* Simple O(N^2) Multiplication +*/ +void bigint_simple_mul(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, x_size + y_size); + + for(size_t i = 0; i != y_size; ++i) + { + const word y_i = y[i]; + + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, y_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +/* +* Simple O(N^2) Squaring +* +* This is exactly the same algorithm as bigint_simple_mul, however +* because C/C++ compilers suck at alias analysis it is good to have +* the version where the compiler knows that x == y +* +* There is an O(n^1.5) squaring algorithm specified in Handbook of +* Applied Cryptography, chapter 14 +* +*/ +void bigint_simple_sqr(word z[], const word x[], size_t x_size) + { + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, 2*x_size); + + for(size_t i = 0; i != x_size; ++i) + { + const word x_i = x[i]; + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, x_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +} + +} diff --git a/src/lib/math/mp/mp_shift.cpp b/src/lib/math/mp/mp_shift.cpp new file mode 100644 index 000000000..0531658ec --- /dev/null +++ b/src/lib/math/mp/mp_shift.cpp @@ -0,0 +1,138 @@ +/* +* MP Shift Algorithms +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +extern "C" { + +/* +* Single Operand Left Shift +*/ +void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) + { + if(word_shift) + { + for(size_t j = 1; j != x_size + 1; ++j) + x[(x_size - j) + word_shift] = x[x_size - j]; + clear_mem(x, word_shift); + } + + if(bit_shift) + { + word carry = 0; + for(size_t j = word_shift; j != x_size + word_shift + 1; ++j) + { + word temp = x[j]; + x[j] = (temp << bit_shift) | carry; + carry = (temp >> (MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Single Operand Right Shift +*/ +void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) + { + if(x_size < word_shift) + { + clear_mem(x, x_size); + return; + } + + if(word_shift) + { + copy_mem(x, x + word_shift, x_size - word_shift); + clear_mem(x + x_size - word_shift, word_shift); + } + + if(bit_shift) + { + word carry = 0; + + size_t top = x_size - word_shift; + + while(top >= 4) + { + word w = x[top-1]; + x[top-1] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + w = x[top-2]; + x[top-2] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + w = x[top-3]; + x[top-3] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + w = x[top-4]; + x[top-4] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + top -= 4; + } + + while(top) + { + word w = x[top-1]; + x[top-1] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + top--; + } + } + } + +/* +* Two Operand Left Shift +*/ +void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + for(size_t j = 0; j != x_size; ++j) + y[j + word_shift] = x[j]; + if(bit_shift) + { + word carry = 0; + for(size_t j = word_shift; j != x_size + word_shift + 1; ++j) + { + word w = y[j]; + y[j] = (w << bit_shift) | carry; + carry = (w >> (MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Two Operand Right Shift +*/ +void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + if(x_size < word_shift) return; + + for(size_t j = 0; j != x_size - word_shift; ++j) + y[j] = x[j + word_shift]; + if(bit_shift) + { + word carry = 0; + for(size_t j = x_size - word_shift; j > 0; --j) + { + word w = y[j-1]; + y[j-1] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + } + } + } + +} + +} diff --git a/src/lib/math/mp/mp_types.h b/src/lib/math/mp/mp_types.h new file mode 100644 index 000000000..60282fb83 --- /dev/null +++ b/src/lib/math/mp/mp_types.h @@ -0,0 +1,46 @@ +/* +* Low Level MPI Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MPI_TYPES_H__ +#define BOTAN_MPI_TYPES_H__ + +#include +#include + +namespace Botan { + +#if (BOTAN_MP_WORD_BITS == 8) + typedef byte word; + typedef u16bit dword; + #define BOTAN_HAS_MP_DWORD +#elif (BOTAN_MP_WORD_BITS == 16) + typedef u16bit word; + typedef u32bit dword; + #define BOTAN_HAS_MP_DWORD +#elif (BOTAN_MP_WORD_BITS == 32) + typedef u32bit word; + typedef u64bit dword; + #define BOTAN_HAS_MP_DWORD +#elif (BOTAN_MP_WORD_BITS == 64) + typedef u64bit word; + + #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + typedef uint128_t dword; + #define BOTAN_HAS_MP_DWORD + #endif + +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +const word MP_WORD_MASK = ~static_cast(0); +const word MP_WORD_TOP_BIT = static_cast(1) << (8*sizeof(word) - 1); +const word MP_WORD_MAX = MP_WORD_MASK; + +} + +#endif diff --git a/src/lib/math/mp/mp_x86_32/info.txt b/src/lib/math/mp/mp_x86_32/info.txt new file mode 100644 index 000000000..f36abaf62 --- /dev/null +++ b/src/lib/math/mp/mp_x86_32/info.txt @@ -0,0 +1,18 @@ +load_on dep + +mp_bits 32 + + +mp_madd.h +mp_asmi.h + + + +x86_32 + + + +clang +gcc +icc + diff --git a/src/lib/math/mp/mp_x86_32/mp_asmi.h b/src/lib/math/mp/mp_x86_32/mp_asmi.h new file mode 100644 index 000000000..9b858c8d5 --- /dev/null +++ b/src/lib/math/mp/mp_x86_32/mp_asmi.h @@ -0,0 +1,240 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H__ +#define BOTAN_MP_ASM_INTERNAL_H__ + +#include + +namespace Botan { + +extern "C" { + +/* +* Helper Macros for x86 Assembly +*/ +#ifndef ASM + #define ASM(x) x "\n\t" +#endif + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \ + ASM("movl %[carry], 4*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("addl 4*" #INDEX "(%[z]),%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX " (%[z])") + +#define DO_8_TIMES(MACRO, ARG) \ + MACRO(ARG, 0) \ + MACRO(ARG, 1) \ + MACRO(ARG, 2) \ + MACRO(ARG, 3) \ + MACRO(ARG, 4) \ + MACRO(ARG, 5) \ + MACRO(ARG, 6) \ + MACRO(ARG, 7) + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorl %[carry]") \ + CORE_CODE \ + ASM("sbbl %[carry],%[carry]") \ + ASM("negl %[carry]") + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { + asm( + ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { + asm( + ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y) + { + asm( + ASM("mull %[y]") + + ASM("addl %[x],%[w0]") + ASM("adcl %[y],%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y) + { + asm( + ASM("mull %[y]") + + ASM("addl %[x],%[w0]") + ASM("adcl %[y],%[w1]") + ASM("adcl $0,%[w2]") + + ASM("addl %[x],%[w0]") + ASM("adcl %[y],%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + } + +} + +} + +#endif diff --git a/src/lib/math/mp/mp_x86_32/mp_madd.h b/src/lib/math/mp/mp_x86_32/mp_madd.h new file mode 100644 index 000000000..9d60c721d --- /dev/null +++ b/src/lib/math/mp/mp_x86_32/mp_madd.h @@ -0,0 +1,67 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2008 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_WORD_MULADD_H__ +#define BOTAN_MP_WORD_MULADD_H__ + +#include + +#if (BOTAN_MP_WORD_BITS != 32) + #error The mp_x86_32 module requires that BOTAN_MP_WORD_BITS == 32 +#endif + +namespace Botan { + +extern "C" { + +/* +* Helper Macros for x86 Assembly +*/ +#define ASM(x) x "\n\t" + +/* +* Word Multiply +*/ +inline word word_madd2(word a, word b, word* c) + { + asm( + ASM("mull %[b]") + ASM("addl %[c],%[a]") + ASM("adcl $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { + asm( + ASM("mull %[b]") + + ASM("addl %[c],%[a]") + ASM("adcl $0,%[carry]") + + ASM("addl %[d],%[a]") + ASM("adcl $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + } + +} + +} + +#endif diff --git a/src/lib/math/mp/mp_x86_32_msvc/info.txt b/src/lib/math/mp/mp_x86_32_msvc/info.txt new file mode 100644 index 000000000..3029d6a61 --- /dev/null +++ b/src/lib/math/mp/mp_x86_32_msvc/info.txt @@ -0,0 +1,16 @@ +mp_bits 32 + +load_on dep + + +mp_generic:mp_madd.h +mp_asmi.h + + + +x86_32 + + + +msvc + diff --git a/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h b/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h new file mode 100644 index 000000000..ef149c920 --- /dev/null +++ b/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h @@ -0,0 +1,542 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H__ +#define BOTAN_MP_ASM_INTERNAL_H__ + +#include + +namespace Botan { + +extern "C" { + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { + word z = x + y; + word c1 = (z < x); + z += *carry; + *carry = c1 | (z < *carry); + return z; + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { + __asm { + mov edx,[x] + mov esi,[y] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov eax,[esi] + adc [edx],eax + mov eax,[esi+4] + adc [edx+4],eax + mov eax,[esi+8] + adc [edx+8],eax + mov eax,[esi+12] + adc [edx+12],eax + mov eax,[esi+16] + adc [edx+16],eax + mov eax,[esi+20] + adc [edx+20],eax + mov eax,[esi+24] + adc [edx+24],eax + mov eax,[esi+28] + adc [edx+28],eax + sbb eax,eax + neg eax + } + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) + { + __asm { + mov edi,[x] + mov esi,[y] + mov ebx,[z] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov eax,[edi] + adc eax,[esi] + mov [ebx],eax + + mov eax,[edi+4] + adc eax,[esi+4] + mov [ebx+4],eax + + mov eax,[edi+8] + adc eax,[esi+8] + mov [ebx+8],eax + + mov eax,[edi+12] + adc eax,[esi+12] + mov [ebx+12],eax + + mov eax,[edi+16] + adc eax,[esi+16] + mov [ebx+16],eax + + mov eax,[edi+20] + adc eax,[esi+20] + mov [ebx+20],eax + + mov eax,[edi+24] + adc eax,[esi+24] + mov [ebx+24],eax + + mov eax,[edi+28] + adc eax,[esi+28] + mov [ebx+28],eax + + sbb eax,eax + neg eax + } + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { + word t0 = x - y; + word c1 = (t0 > x); + word z = t0 - *carry; + *carry = c1 | (z > t0); + return z; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { + __asm { + mov edi,[x] + mov esi,[y] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov eax,[edi] + sbb eax,[esi] + mov [edi],eax + mov eax,[edi+4] + sbb eax,[esi+4] + mov [edi+4],eax + mov eax,[edi+8] + sbb eax,[esi+8] + mov [edi+8],eax + mov eax,[edi+12] + sbb eax,[esi+12] + mov [edi+12],eax + mov eax,[edi+16] + sbb eax,[esi+16] + mov [edi+16],eax + mov eax,[edi+20] + sbb eax,[esi+20] + mov [edi+20],eax + mov eax,[edi+24] + sbb eax,[esi+24] + mov [edi+24],eax + mov eax,[edi+28] + sbb eax,[esi+28] + mov [edi+28],eax + sbb eax,eax + neg eax + } + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { + x[0] = word_sub(y[0], x[0], &carry); + x[1] = word_sub(y[1], x[1], &carry); + x[2] = word_sub(y[2], x[2], &carry); + x[3] = word_sub(y[3], x[3], &carry); + x[4] = word_sub(y[4], x[4], &carry); + x[5] = word_sub(y[5], x[5], &carry); + x[6] = word_sub(y[6], x[6], &carry); + x[7] = word_sub(y[7], x[7], &carry); + return carry; + } + + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], + const word y[8], word carry) + { + __asm { + mov edi,[x] + mov esi,[y] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov ebx,[z] + mov eax,[edi] + sbb eax,[esi] + mov [ebx],eax + mov eax,[edi+4] + sbb eax,[esi+4] + mov [ebx+4],eax + mov eax,[edi+8] + sbb eax,[esi+8] + mov [ebx+8],eax + mov eax,[edi+12] + sbb eax,[esi+12] + mov [ebx+12],eax + mov eax,[edi+16] + sbb eax,[esi+16] + mov [ebx+16],eax + mov eax,[edi+20] + sbb eax,[esi+20] + mov [ebx+20],eax + mov eax,[edi+24] + sbb eax,[esi+24] + mov [ebx+24],eax + mov eax,[edi+28] + sbb eax,[esi+28] + mov [ebx+28],eax + sbb eax,eax + neg eax + } + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { + __asm { + mov esi,[x] + mov eax,[esi] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,[carry] //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi],eax //load a + + mov eax,[esi+4] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+4],eax //load a + + mov eax,[esi+8] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+8],eax //load a + + mov eax,[esi+12] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+12],eax //load a + + mov eax,[esi+16] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+16],eax //load a + + mov eax,[esi+20] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+20],eax //load a + + mov eax,[esi+24] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+24],eax //load a + + mov eax,[esi+28] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov [esi+28],eax //load a + + mov eax,edx //store carry + } + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_muladd(word z[8], const word x[8], + word y, word carry) + { + __asm { + mov esi,[x] + mov ebx,[y] + mov edi,[z] + mov eax,[esi] //load a + mul ebx //edx(hi):eax(lo)=a*b + add eax,[carry] //sum lo carry + adc edx,0 //sum hi carry + add eax,[edi] //sum lo z + adc edx,0 //sum hi z + mov ecx,edx //carry for next block = hi z + mov [edi],eax //save lo z + + mov eax,[esi+4] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+4] + adc edx,0 + mov ecx,edx + mov [edi+4],eax + + mov eax,[esi+8] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+8] + adc edx,0 + mov ecx,edx + mov [edi+8],eax + + mov eax,[esi+12] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+12] + adc edx,0 + mov ecx,edx + mov [edi+12],eax + + mov eax,[esi+16] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+16] + adc edx,0 + mov ecx,edx + mov [edi+16],eax + + mov eax,[esi+20] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+20] + adc edx,0 + mov ecx,edx + mov [edi+20],eax + + mov eax,[esi+24] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+24] + adc edx,0 + mov ecx,edx + mov [edi+24],eax + + mov eax,[esi+28] + mul ebx + add eax,ecx + adc edx,0 + add eax,[edi+28] + adc edx,0 + mov [edi+28],eax + mov eax,edx + } + } + +inline word word8_linmul3(word z[4], const word x[4], word y, word carry) + { + __asm { +#if 0 + //it's slower!!! + mov edx,[z] + mov eax,[x] + movd mm7,[y] + + movd mm0,[eax] + movd mm1,[eax+4] + movd mm2,[eax+8] + pmuludq mm0,mm7 + pmuludq mm1,mm7 + pmuludq mm2,mm7 + + movd mm6,[carry] + paddq mm0,mm6 + movd [edx],mm0 + + psrlq mm0,32 + paddq mm1,mm0 + movd [edx+4],mm1 + + movd mm3,[eax+12] + psrlq mm1,32 + paddq mm2,mm1 + movd [edx+8],mm2 + + pmuludq mm3,mm7 + movd mm4,[eax+16] + psrlq mm2,32 + paddq mm3,mm2 + movd [edx+12],mm3 + + pmuludq mm4,mm7 + movd mm5,[eax+20] + psrlq mm3,32 + paddq mm4,mm3 + movd [edx+16],mm4 + + pmuludq mm5,mm7 + movd mm0,[eax+24] + psrlq mm4,32 + paddq mm5,mm4 + movd [edx+20],mm5 + + pmuludq mm0,mm7 + movd mm1,[eax+28] + psrlq mm5,32 + paddq mm0,mm5 + movd [edx+24],mm0 + + pmuludq mm1,mm7 + psrlq mm0,32 + paddq mm1,mm0 + movd [edx+28],mm1 + psrlq mm1,32 + + movd eax,mm1 + emms +#else + mov edi,[z] + mov esi,[x] + mov eax,[esi] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,[carry] //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi],eax //load a + + mov eax,[esi+4] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+4],eax //load a + + mov eax,[esi+8] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+8],eax //load a + + mov eax,[esi+12] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+12],eax //load a + + mov eax,[esi+16] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+16],eax //load a + + mov eax,[esi+20] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+20],eax //load a + + mov eax,[esi+24] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+24],eax //load a + + mov eax,[esi+28] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov [edi+28],eax //load a + mov eax,edx //store carry +#endif + } + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { + z[0] = word_madd3(x[0], y, z[0], &carry); + z[1] = word_madd3(x[1], y, z[1], &carry); + z[2] = word_madd3(x[2], y, z[2], &carry); + z[3] = word_madd3(x[3], y, z[3], &carry); + z[4] = word_madd3(x[4], y, z[4], &carry); + z[5] = word_madd3(x[5], y, z[5], &carry); + z[6] = word_madd3(x[6], y, z[6], &carry); + z[7] = word_madd3(x[7], y, z[7], &carry); + return carry; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b) + { + word carry = *w0; + *w0 = word_madd2(a, b, &carry); + *w1 += carry; + *w2 += (*w1 < carry) ? 1 : 0; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b) + { + word carry = 0; + a = word_madd2(a, b, &carry); + b = carry; + + word top = (b >> (BOTAN_MP_WORD_BITS-1)); + b <<= 1; + b |= (a >> (BOTAN_MP_WORD_BITS-1)); + a <<= 1; + + carry = 0; + *w0 = word_add(*w0, a, &carry); + *w1 = word_add(*w1, b, &carry); + *w2 = word_add(*w2, top, &carry); + } + +} + +} + +#endif diff --git a/src/lib/math/mp/mp_x86_64/info.txt b/src/lib/math/mp/mp_x86_64/info.txt new file mode 100644 index 000000000..75c42ddc1 --- /dev/null +++ b/src/lib/math/mp/mp_x86_64/info.txt @@ -0,0 +1,18 @@ +load_on dep + +mp_bits 64 + + +mp_madd.h +mp_asmi.h + + + +x86_64 + + + +clang +gcc +icc + diff --git a/src/lib/math/mp/mp_x86_64/mp_asmi.h b/src/lib/math/mp/mp_x86_64/mp_asmi.h new file mode 100644 index 000000000..b2f1202e3 --- /dev/null +++ b/src/lib/math/mp/mp_x86_64/mp_asmi.h @@ -0,0 +1,248 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H__ +#define BOTAN_MP_ASM_INTERNAL_H__ + +#include + +namespace Botan { + +extern "C" { + +/* +* Helper Macros for x86-64 Assembly +*/ +#ifndef ASM + #define ASM(x) x "\n\t" +#endif + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movq 8*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 8*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 8*" #INDEX "(%[y]), %[carry]") \ + ASM("movq %[carry], 8*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]),%%rax") \ + ASM("mulq %[y]") \ + ASM("addq %[carry],%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("movq %%rdx,%[carry]") \ + ASM("movq %%rax, 8*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]),%%rax") \ + ASM("mulq %[y]") \ + ASM("addq %[carry],%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("addq 8*" #INDEX "(%[z]),%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("movq %%rdx,%[carry]") \ + ASM("movq %%rax, 8*" #INDEX " (%[z])") + +#define DO_8_TIMES(MACRO, ARG) \ + MACRO(ARG, 0) \ + MACRO(ARG, 1) \ + MACRO(ARG, 2) \ + MACRO(ARG, 3) \ + MACRO(ARG, 4) \ + MACRO(ARG, 5) \ + MACRO(ARG, 6) \ + MACRO(ARG, 7) + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorq %[carry]") \ + CORE_CODE \ + ASM("sbbq %[carry],%[carry]") \ + ASM("negq %[carry]") + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { + asm( + ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { + asm( + ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y) + { + asm( + ASM("mulq %[y]") + + ASM("addq %[x],%[w0]") + ASM("adcq %[y],%[w1]") + ASM("adcq $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y) + { + asm( + ASM("mulq %[y]") + + ASM("addq %[x],%[w0]") + ASM("adcq %[y],%[w1]") + ASM("adcq $0,%[w2]") + + ASM("addq %[x],%[w0]") + ASM("adcq %[y],%[w1]") + ASM("adcq $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + } + + +#undef ASM +#undef DO_8_TIMES +#undef ADD_OR_SUBTRACT +#undef ADDSUB2_OP +#undef ADDSUB3_OP +#undef LINMUL_OP +#undef MULADD_OP + +} + +} +#endif diff --git a/src/lib/math/mp/mp_x86_64/mp_madd.h b/src/lib/math/mp/mp_x86_64/mp_madd.h new file mode 100644 index 000000000..4c0d79931 --- /dev/null +++ b/src/lib/math/mp/mp_x86_64/mp_madd.h @@ -0,0 +1,69 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2008 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MP_WORD_MULADD_H__ +#define BOTAN_MP_WORD_MULADD_H__ + +#include + +#if (BOTAN_MP_WORD_BITS != 64) + #error The mp_x86_64 module requires that BOTAN_MP_WORD_BITS == 64 +#endif + +namespace Botan { + +extern "C" { + +/* +* Helper Macros for x86-64 Assembly +*/ +#define ASM(x) x "\n\t" + +/* +* Word Multiply +*/ +inline word word_madd2(word a, word b, word* c) + { + asm( + ASM("mulq %[b]") + ASM("addq %[c],%[a]") + ASM("adcq $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { + asm( + ASM("mulq %[b]") + + ASM("addq %[c],%[a]") + ASM("adcq $0,%[carry]") + + ASM("addq %[d],%[a]") + ASM("adcq $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + } + +#undef ASM + +} + +} + +#endif diff --git a/src/lib/math/numbertheory/def_powm.h b/src/lib/math/numbertheory/def_powm.h new file mode 100644 index 000000000..6ceee7bb6 --- /dev/null +++ b/src/lib/math/numbertheory/def_powm.h @@ -0,0 +1,63 @@ +/* +* Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DEFAULT_MODEXP_H__ +#define BOTAN_DEFAULT_MODEXP_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Fixed Window Exponentiator +*/ +class Fixed_Window_Exponentiator : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt&); + void set_base(const BigInt&); + BigInt execute() const; + + Modular_Exponentiator* copy() const + { return new Fixed_Window_Exponentiator(*this); } + + Fixed_Window_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + Modular_Reducer reducer; + BigInt exp; + size_t window_bits; + std::vector g; + Power_Mod::Usage_Hints hints; + }; + +/** +* Montgomery Exponentiator +*/ +class Montgomery_Exponentiator : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt&); + void set_base(const BigInt&); + BigInt execute() const; + + Modular_Exponentiator* copy() const + { return new Montgomery_Exponentiator(*this); } + + Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + BigInt m_exp, m_modulus, m_R_mod, m_R2_mod; + word m_mod_prime; + size_t m_mod_words, m_exp_bits, m_window_bits; + Power_Mod::Usage_Hints m_hints; + std::vector m_g; + }; + +} + +#endif diff --git a/src/lib/math/numbertheory/dsa_gen.cpp b/src/lib/math/numbertheory/dsa_gen.cpp new file mode 100644 index 000000000..d30a08f1a --- /dev/null +++ b/src/lib/math/numbertheory/dsa_gen.cpp @@ -0,0 +1,134 @@ +/* +* DSA Parameter Generation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Check if this size is allowed by FIPS 186-3 +*/ +bool fips186_3_valid_size(size_t pbits, size_t qbits) + { + if(qbits == 160) + return (pbits == 512 || pbits == 768 || pbits == 1024); + + if(qbits == 224) + return (pbits == 2048); + + if(qbits == 256) + return (pbits == 2048 || pbits == 3072); + + return false; + } + +} + +/* +* Attempt DSA prime generation with given seed +*/ +bool generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits, + const std::vector& seed_c) + { + if(!fips186_3_valid_size(pbits, qbits)) + throw Invalid_Argument( + "FIPS 186-3 does not allow DSA domain parameters of " + + std::to_string(pbits) + "/" + std::to_string(qbits) + " bits long"); + + if(seed_c.size() * 8 < qbits) + throw Invalid_Argument( + "Generating a DSA parameter set with a " + std::to_string(qbits) + + "long q requires a seed at least as many bits long"); + + std::unique_ptr hash( + af.make_hash_function("SHA-" + std::to_string(qbits))); + + const size_t HASH_SIZE = hash->output_length(); + + class Seed + { + public: + Seed(const std::vector& s) : seed(s) {} + + operator std::vector& () { return seed; } + + Seed& operator++() + { + for(size_t j = seed.size(); j > 0; --j) + if(++seed[j-1]) + break; + return (*this); + } + private: + std::vector seed; + }; + + Seed seed(seed_c); + + q.binary_decode(hash->process(seed)); + q.set_bit(qbits-1); + q.set_bit(0); + + if(!check_prime(q, rng)) + return false; + + const size_t n = (pbits-1) / (HASH_SIZE * 8), + b = (pbits-1) % (HASH_SIZE * 8); + + BigInt X; + std::vector V(HASH_SIZE * (n+1)); + + for(size_t j = 0; j != 4096; ++j) + { + for(size_t k = 0; k <= n; ++k) + { + ++seed; + hash->update(seed); + hash->final(&V[HASH_SIZE * (n-k)]); + } + + X.binary_decode(&V[HASH_SIZE - 1 - b/8], + V.size() - (HASH_SIZE - 1 - b/8)); + X.set_bit(pbits-1); + + p = X - (X % (2*q) - 1); + + if(p.bits() == pbits && check_prime(p, rng)) + return true; + } + return false; + } + +/* +* Generate DSA Primes +*/ +std::vector generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits) + { + while(true) + { + std::vector seed(qbits / 8); + rng.randomize(&seed[0], seed.size()); + + if(generate_dsa_primes(rng, af, p, q, pbits, qbits, seed)) + return seed; + } + } + +} diff --git a/src/lib/math/numbertheory/info.txt b/src/lib/math/numbertheory/info.txt new file mode 100644 index 000000000..62386c3bc --- /dev/null +++ b/src/lib/math/numbertheory/info.txt @@ -0,0 +1,35 @@ +define BIGINT_MATH 20131128 + +load_on auto + + +numthry.h +pow_mod.h +reducer.h + + + +def_powm.h + + + +dsa_gen.cpp +jacobi.cpp +make_prm.cpp +mp_numth.cpp +numthry.cpp +pow_mod.cpp +powm_fw.cpp +powm_mnt.cpp +primes.cpp +reducer.cpp +ressol.cpp + + + +algo_factory +bigint +hash +libstate +rng + diff --git a/src/lib/math/numbertheory/jacobi.cpp b/src/lib/math/numbertheory/jacobi.cpp new file mode 100644 index 000000000..fcccc80e5 --- /dev/null +++ b/src/lib/math/numbertheory/jacobi.cpp @@ -0,0 +1,53 @@ +/* +* Jacobi Function +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Calculate the Jacobi symbol +*/ +s32bit jacobi(const BigInt& a, const BigInt& n) + { + if(a.is_negative()) + throw Invalid_Argument("jacobi: first argument must be non-negative"); + if(n.is_even() || n < 2) + throw Invalid_Argument("jacobi: second argument must be odd and > 1"); + + BigInt x = a, y = n; + s32bit J = 1; + + while(y > 1) + { + x %= y; + if(x > y / 2) + { + x = y - x; + if(y % 4 == 3) + J = -J; + } + if(x.is_zero()) + return 0; + + size_t shifts = low_zero_bits(x); + x >>= shifts; + if(shifts % 2) + { + word y_mod_8 = y % 8; + if(y_mod_8 == 3 || y_mod_8 == 5) + J = -J; + } + + if(x % 4 == 3 && y % 4 == 3) + J = -J; + std::swap(x, y); + } + return J; + } + +} diff --git a/src/lib/math/numbertheory/make_prm.cpp b/src/lib/math/numbertheory/make_prm.cpp new file mode 100644 index 000000000..dc94420ab --- /dev/null +++ b/src/lib/math/numbertheory/make_prm.cpp @@ -0,0 +1,100 @@ +/* +* Prime Generation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Generate a random prime +*/ +BigInt random_prime(RandomNumberGenerator& rng, + size_t bits, const BigInt& coprime, + size_t equiv, size_t modulo) + { + if(bits <= 1) + throw Invalid_Argument("random_prime: Can't make a prime of " + + std::to_string(bits) + " bits"); + else if(bits == 2) + return ((rng.next_byte() % 2) ? 2 : 3); + else if(bits == 3) + return ((rng.next_byte() % 2) ? 5 : 7); + else if(bits == 4) + return ((rng.next_byte() % 2) ? 11 : 13); + + if(coprime <= 0) + throw Invalid_Argument("random_prime: coprime must be > 0"); + if(modulo % 2 == 1 || modulo == 0) + throw Invalid_Argument("random_prime: Invalid modulo value"); + if(equiv >= modulo || equiv % 2 == 0) + throw Invalid_Argument("random_prime: equiv must be < modulo, and odd"); + + while(true) + { + BigInt p(rng, bits); + + // Force lowest and two top bits on + p.set_bit(bits - 1); + p.set_bit(bits - 2); + p.set_bit(0); + + if(p % modulo != equiv) + p += (modulo - p % modulo) + equiv; + + const size_t sieve_size = std::min(bits / 2, PRIME_TABLE_SIZE); + secure_vector sieve(sieve_size); + + for(size_t j = 0; j != sieve.size(); ++j) + sieve[j] = p % PRIMES[j]; + + size_t counter = 0; + while(true) + { + if(counter == 4096 || p.bits() > bits) + break; + + bool passes_sieve = true; + ++counter; + p += modulo; + + if(p.bits() > bits) + break; + + for(size_t j = 0; j != sieve.size(); ++j) + { + sieve[j] = (sieve[j] + modulo) % PRIMES[j]; + if(sieve[j] == 0) + passes_sieve = false; + } + + if(!passes_sieve || gcd(p - 1, coprime) != 1) + continue; + if(check_prime(p, rng)) + return p; + } + } + } + +/* +* Generate a random safe prime +*/ +BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) + { + if(bits <= 64) + throw Invalid_Argument("random_safe_prime: Can't make a prime of " + + std::to_string(bits) + " bits"); + + BigInt p; + do + p = (random_prime(rng, bits - 1) << 1) + 1; + while(!check_prime(p, rng)); + return p; + } + +} diff --git a/src/lib/math/numbertheory/mp_numth.cpp b/src/lib/math/numbertheory/mp_numth.cpp new file mode 100644 index 000000000..e6826b9dd --- /dev/null +++ b/src/lib/math/numbertheory/mp_numth.cpp @@ -0,0 +1,74 @@ +/* +* Fused and Important MP Algorithms +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Square a BigInt +*/ +BigInt square(const BigInt& x) + { + const size_t x_sw = x.sig_words(); + + BigInt z(BigInt::Positive, round_up(2*x_sw, 16)); + secure_vector workspace(z.size()); + + bigint_sqr(z.mutable_data(), z.size(), + &workspace[0], + x.data(), x.size(), x_sw); + return z; + } + +/* +* Multiply-Add Operation +*/ +BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative() || c.is_zero()) + throw Invalid_Argument("mul_add: Third argument must be > 0"); + + BigInt::Sign sign = BigInt::Positive; + if(a.sign() != b.sign()) + sign = BigInt::Negative; + + const size_t a_sw = a.sig_words(); + const size_t b_sw = b.sig_words(); + const size_t c_sw = c.sig_words(); + + BigInt r(sign, std::max(a.size() + b.size(), c_sw) + 1); + secure_vector workspace(r.size()); + + bigint_mul(r.mutable_data(), r.size(), + &workspace[0], + a.data(), a.size(), a_sw, + b.data(), b.size(), b_sw); + + const size_t r_size = std::max(r.sig_words(), c_sw); + bigint_add2(r.mutable_data(), r_size, c.data(), c_sw); + return r; + } + +/* +* Subtract-Multiply Operation +*/ +BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(a.is_negative() || b.is_negative()) + throw Invalid_Argument("sub_mul: First two arguments must be >= 0"); + + BigInt r = a; + r -= b; + r *= c; + return r; + } + +} diff --git a/src/lib/math/numbertheory/numthry.cpp b/src/lib/math/numbertheory/numthry.cpp new file mode 100644 index 000000000..e3c673ea5 --- /dev/null +++ b/src/lib/math/numbertheory/numthry.cpp @@ -0,0 +1,409 @@ +/* +* Number Theory Functions +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Miller-Rabin Primality Tester +*/ +class MillerRabin_Test + { + public: + bool is_witness(const BigInt& nonce); + MillerRabin_Test(const BigInt& num); + private: + BigInt n, r, n_minus_1; + size_t s; + Fixed_Exponent_Power_Mod pow_mod; + Modular_Reducer reducer; + }; + +/* +* Miller-Rabin Test, as described in Handbook of Applied Cryptography +* section 4.24 +*/ +bool MillerRabin_Test::is_witness(const BigInt& a) + { + if(a < 2 || a >= n_minus_1) + throw Invalid_Argument("Bad size for nonce in Miller-Rabin test"); + + BigInt y = pow_mod(a); + if(y == 1 || y == n_minus_1) + return false; + + for(size_t i = 1; i != s; ++i) + { + y = reducer.square(y); + + if(y == 1) // found a non-trivial square root + return true; + + if(y == n_minus_1) // -1, trivial square root, so give up + return false; + } + + if(y != n_minus_1) // fails Fermat test + return true; + + return false; + } + +/* +* Miller-Rabin Constructor +*/ +MillerRabin_Test::MillerRabin_Test(const BigInt& num) + { + if(num.is_even() || num < 3) + throw Invalid_Argument("MillerRabin_Test: Invalid number for testing"); + + n = num; + n_minus_1 = n - 1; + s = low_zero_bits(n_minus_1); + r = n_minus_1 >> s; + + pow_mod = Fixed_Exponent_Power_Mod(r, n); + reducer = Modular_Reducer(n); + } + +/* +* Miller-Rabin Iterations +*/ +size_t miller_rabin_test_iterations(size_t bits, size_t level) + { + struct mapping { size_t bits; size_t verify_iter; size_t check_iter; }; + + const mapping tests[] = { + { 50, 55, 25 }, + { 100, 38, 22 }, + { 160, 32, 18 }, + { 163, 31, 17 }, + { 168, 30, 16 }, + { 177, 29, 16 }, + { 181, 28, 15 }, + { 185, 27, 15 }, + { 190, 26, 15 }, + { 195, 25, 14 }, + { 201, 24, 14 }, + { 208, 23, 14 }, + { 215, 22, 13 }, + { 222, 21, 13 }, + { 231, 20, 13 }, + { 241, 19, 12 }, + { 252, 18, 12 }, + { 264, 17, 12 }, + { 278, 16, 11 }, + { 294, 15, 10 }, + { 313, 14, 9 }, + { 334, 13, 8 }, + { 360, 12, 8 }, + { 392, 11, 7 }, + { 430, 10, 7 }, + { 479, 9, 6 }, + { 542, 8, 6 }, + { 626, 7, 5 }, + { 746, 6, 4 }, + { 926, 5, 3 }, + { 1232, 4, 2 }, + { 1853, 3, 2 }, + { 0, 0, 0 } + }; + + for(size_t i = 0; tests[i].bits; ++i) + { + if(bits <= tests[i].bits) + { + if(level >= 2) + return tests[i].verify_iter; + else if(level == 1) + return tests[i].check_iter; + else if(level == 0) + return std::max(tests[i].check_iter / 4, 1); + } + } + + return level > 0 ? 2 : 1; // for large inputs + } + +} + +/* +* Return the number of 0 bits at the end of n +*/ +size_t low_zero_bits(const BigInt& n) + { + size_t low_zero = 0; + + if(n.is_positive() && n.is_nonzero()) + { + for(size_t i = 0; i != n.size(); ++i) + { + const word x = n.word_at(i); + + if(x) + { + low_zero += ctz(x); + break; + } + else + low_zero += BOTAN_MP_WORD_BITS; + } + } + + return low_zero; + } + +/* +* Calculate the GCD +*/ +BigInt gcd(const BigInt& a, const BigInt& b) + { + if(a.is_zero() || b.is_zero()) return 0; + if(a == 1 || b == 1) return 1; + + BigInt x = a, y = b; + x.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + size_t shift = std::min(low_zero_bits(x), low_zero_bits(y)); + + x >>= shift; + y >>= shift; + + while(x.is_nonzero()) + { + x >>= low_zero_bits(x); + y >>= low_zero_bits(y); + if(x >= y) { x -= y; x >>= 1; } + else { y -= x; y >>= 1; } + } + + return (y << shift); + } + +/* +* Calculate the LCM +*/ +BigInt lcm(const BigInt& a, const BigInt& b) + { + return ((a * b) / gcd(a, b)); + } + +namespace { + +/* +* If the modulus is odd, then we can avoid computing A and C. This is +* a critical path algorithm in some instances and an odd modulus is +* the common case for crypto, so worth special casing. See note 14.64 +* in Handbook of Applied Cryptography for more details. +*/ +BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) + { + BigInt u = mod, v = n; + BigInt B = 0, D = 1; + + while(u.is_nonzero()) + { + const size_t u_zero_bits = low_zero_bits(u); + u >>= u_zero_bits; + for(size_t i = 0; i != u_zero_bits; ++i) + { + if(B.is_odd()) + { B -= mod; } + B >>= 1; + } + + const size_t v_zero_bits = low_zero_bits(v); + v >>= v_zero_bits; + for(size_t i = 0; i != v_zero_bits; ++i) + { + if(D.is_odd()) + { D -= mod; } + D >>= 1; + } + + if(u >= v) { u -= v; B -= D; } + else { v -= u; D -= B; } + } + + if(v != 1) + return 0; // no modular inverse + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +} + +/* +* Find the Modular Inverse +*/ +BigInt inverse_mod(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative() || n.is_negative()) + throw Invalid_Argument("inverse_mod: arguments must be non-negative"); + + if(n.is_zero() || (n.is_even() && mod.is_even())) + return 0; // fast fail checks + + if(mod.is_odd()) + return inverse_mod_odd_modulus(n, mod); + + BigInt u = mod, v = n; + BigInt A = 1, B = 0, C = 0, D = 1; + + while(u.is_nonzero()) + { + const size_t u_zero_bits = low_zero_bits(u); + u >>= u_zero_bits; + for(size_t i = 0; i != u_zero_bits; ++i) + { + if(A.is_odd() || B.is_odd()) + { A += n; B -= mod; } + A >>= 1; B >>= 1; + } + + const size_t v_zero_bits = low_zero_bits(v); + v >>= v_zero_bits; + for(size_t i = 0; i != v_zero_bits; ++i) + { + if(C.is_odd() || D.is_odd()) + { C += n; D -= mod; } + C >>= 1; D >>= 1; + } + + if(u >= v) { u -= v; A -= C; B -= D; } + else { v -= u; C -= A; D -= B; } + } + + if(v != 1) + return 0; // no modular inverse + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +word monty_inverse(word input) + { + word b = input; + word x2 = 1, x1 = 0, y2 = 0, y1 = 1; + + // First iteration, a = n+1 + word q = bigint_divop(1, 0, b); + word r = (MP_WORD_MAX - q*b) + 1; + word x = x2 - q*x1; + word y = y2 - q*y1; + + word a = b; + b = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + + while(b > 0) + { + q = a / b; + r = a - q*b; + x = x2 - q*x1; + y = y2 - q*y1; + + a = b; + b = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + + // Now invert in addition space + y2 = (MP_WORD_MAX - y2) + 1; + + return y2; + } + +/* +* Modular Exponentiation +*/ +BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) + { + Power_Mod pow_mod(mod); + + /* + * Calling set_base before set_exponent means we end up using a + * minimal window. This makes sense given that here we know that any + * precomputation is wasted. + */ + pow_mod.set_base(base); + pow_mod.set_exponent(exp); + return pow_mod.execute(); + } + +/* +* Test for primaility using Miller-Rabin +*/ +bool primality_test(const BigInt& n, + RandomNumberGenerator& rng, + size_t level) + { + if(n == 2) + return true; + if(n <= 1 || n.is_even()) + return false; + + // Fast path testing for small numbers (<= 65521) + if(n <= PRIMES[PRIME_TABLE_SIZE-1]) + { + const word num = n.word_at(0); + + for(size_t i = 0; PRIMES[i]; ++i) + { + if(num == PRIMES[i]) + return true; + if(num < PRIMES[i]) + return false; + } + + return false; + } + + if(level > 2) + level = 2; + + const size_t PREF_NONCE_BITS = 192; + + const size_t NONCE_BITS = std::min(n.bits() - 2, PREF_NONCE_BITS); + + MillerRabin_Test mr(n); + + const size_t tests = miller_rabin_test_iterations(n.bits(), level); + + BigInt nonce; + for(size_t i = 0; i != tests; ++i) + { + while(nonce < 2 || nonce >= (n-1)) + nonce.randomize(rng, NONCE_BITS); + + if(mr.is_witness(nonce)) + return false; + } + return true; + } + +} diff --git a/src/lib/math/numbertheory/numthry.h b/src/lib/math/numbertheory/numthry.h new file mode 100644 index 000000000..a34d855b2 --- /dev/null +++ b/src/lib/math/numbertheory/numthry.h @@ -0,0 +1,237 @@ +/* +* Number Theory Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NUMBER_THEORY_H__ +#define BOTAN_NUMBER_THEORY_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Fused multiply-add +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)+c +*/ +BigInt BOTAN_DLL mul_add(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Fused subtract-multiply +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a-b)*c +*/ +BigInt BOTAN_DLL sub_mul(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Return the absolute value +* @param n an integer +* @return absolute value of n +*/ +inline BigInt abs(const BigInt& n) { return n.abs(); } + +/** +* Compute the greatest common divisor +* @param x a positive integer +* @param y a positive integer +* @return gcd(x,y) +*/ +BigInt BOTAN_DLL gcd(const BigInt& x, const BigInt& y); + +/** +* Least common multiple +* @param x a positive integer +* @param y a positive integer +* @return z, smallest integer such that z % x == 0 and z % y == 0 +*/ +BigInt BOTAN_DLL lcm(const BigInt& x, const BigInt& y); + +/** +* @param x an integer +* @return (x*x) +*/ +BigInt BOTAN_DLL square(const BigInt& x); + +/** +* Modular inversion +* @param x a positive integer +* @param modulus a positive integer +* @return y st (x*y) % modulus == 1 +*/ +BigInt BOTAN_DLL inverse_mod(const BigInt& x, + const BigInt& modulus); + +/** +* Compute the Jacobi symbol. If n is prime, this is equivalent +* to the Legendre symbol. +* @see http://mathworld.wolfram.com/JacobiSymbol.html +* +* @param a is a non-negative integer +* @param n is an odd integer > 1 +* @return (n / m) +*/ +s32bit BOTAN_DLL jacobi(const BigInt& a, + const BigInt& n); + +/** +* Modular exponentation +* @param b an integer base +* @param x a positive exponent +* @param m a positive modulus +* @return (b^x) % m +*/ +BigInt BOTAN_DLL power_mod(const BigInt& b, + const BigInt& x, + const BigInt& m); + +/** +* Compute the square root of x modulo a prime using the +* Shanks-Tonnelli algorithm +* +* @param x the input +* @param p the prime +* @return y such that (y*y)%p == x, or -1 if no such integer +*/ +BigInt BOTAN_DLL ressol(const BigInt& x, const BigInt& p); + +/* +* Compute -input^-1 mod 2^MP_WORD_BITS. Returns zero if input +* is even. If input is odd, input and 2^n are relatively prime +* and an inverse exists. +*/ +word BOTAN_DLL monty_inverse(word input); + +/** +* @param x a positive integer +* @return count of the zero bits in x, or, equivalently, the largest +* value of n such that 2^n divides x evenly. Returns zero if +* n is less than or equal to zero. +*/ +size_t BOTAN_DLL low_zero_bits(const BigInt& x); + +/** +* Primality Testing +* @param n a positive integer to test for primality +* @param rng a random number generator +* @param level how hard to test +* @return true if all primality tests passed, otherwise false +*/ +bool BOTAN_DLL primality_test(const BigInt& n, + RandomNumberGenerator& rng, + size_t level = 1); + +/** +* Quickly check for primality +* @param n a positive integer to test for primality +* @param rng a random number generator +* @return true if all primality tests passed, otherwise false +*/ +inline bool quick_check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return primality_test(n, rng, 0); } + +/** +* Check for primality +* @param n a positive integer to test for primality +* @param rng a random number generator +* @return true if all primality tests passed, otherwise false +*/ +inline bool check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return primality_test(n, rng, 1); } + +/** +* Verify primality - this function is slow but useful if you want to +* ensure that a possibly malicious entity did not provide you with +* something that 'looks like' a prime +* @param n a positive integer to test for primality +* @param rng a random number generator +* @return true if all primality tests passed, otherwise false +*/ +inline bool verify_prime(const BigInt& n, RandomNumberGenerator& rng) + { return primality_test(n, rng, 2); } + +/** +* Randomly generate a prime +* @param rng a random number generator +* @param bits how large the resulting prime should be in bits +* @param coprime a positive integer the result should be coprime to +* @param equiv a non-negative number that the result should be + equivalent to modulo equiv_mod +* @param equiv_mod the modulus equiv should be checked against +* @return random prime with the specified criteria +*/ +BigInt BOTAN_DLL random_prime(RandomNumberGenerator& rng, + size_t bits, const BigInt& coprime = 1, + size_t equiv = 1, size_t equiv_mod = 2); + +/** +* Return a 'safe' prime, of the form p=2*q+1 with q prime +* @param rng a random number generator +* @param bits is how long the resulting prime should be +* @return prime randomly chosen from safe primes of length bits +*/ +BigInt BOTAN_DLL random_safe_prime(RandomNumberGenerator& rng, + size_t bits); + +class Algorithm_Factory; + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param af an algorithm factory +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @return random seed used to generate this parameter set +*/ +std::vector BOTAN_DLL +generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits); + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param af an algorithm factory +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @param seed the seed used to generate the parameters +* @return true if seed generated a valid DSA parameter set, otherwise + false. p_out and q_out are only valid if true was returned. +*/ +bool BOTAN_DLL +generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits, + const std::vector& seed); + +/** +* The size of the PRIMES[] array +*/ +const size_t PRIME_TABLE_SIZE = 6541; + +/** +* A const array of all primes less than 65535 +*/ +extern const u16bit BOTAN_DLL PRIMES[]; + +} + +#endif diff --git a/src/lib/math/numbertheory/pow_mod.cpp b/src/lib/math/numbertheory/pow_mod.cpp new file mode 100644 index 000000000..c7d7fe70e --- /dev/null +++ b/src/lib/math/numbertheory/pow_mod.cpp @@ -0,0 +1,211 @@ +/* +* Modular Exponentiation Proxy +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Power_Mod Constructor +*/ +Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints) + { + core = nullptr; + set_modulus(n, hints); + } + +/* +* Power_Mod Copy Constructor +*/ +Power_Mod::Power_Mod(const Power_Mod& other) + { + core = nullptr; + if(other.core) + core = other.core->copy(); + } + +/* +* Power_Mod Assignment Operator +*/ +Power_Mod& Power_Mod::operator=(const Power_Mod& other) + { + delete core; + core = nullptr; + if(other.core) + core = other.core->copy(); + return (*this); + } + +/* +* Power_Mod Destructor +*/ +Power_Mod::~Power_Mod() + { + delete core; + } + +/* +* Set the modulus +*/ +void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints) const + { + delete core; + core = nullptr; + + if(n != 0) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + while(const Engine* engine = i.next()) + { + core = engine->mod_exp(n, hints); + + if(core) + break; + } + + if(!core) + throw Lookup_Error("Power_Mod: Unable to find a working engine"); + } + } + +/* +* Set the base +*/ +void Power_Mod::set_base(const BigInt& b) const + { + if(b.is_zero() || b.is_negative()) + throw Invalid_Argument("Power_Mod::set_base: arg must be > 0"); + + if(!core) + throw Internal_Error("Power_Mod::set_base: core was NULL"); + core->set_base(b); + } + +/* +* Set the exponent +*/ +void Power_Mod::set_exponent(const BigInt& e) const + { + if(e.is_negative()) + throw Invalid_Argument("Power_Mod::set_exponent: arg must be > 0"); + + if(!core) + throw Internal_Error("Power_Mod::set_exponent: core was NULL"); + core->set_exponent(e); + } + +/* +* Compute the result +*/ +BigInt Power_Mod::execute() const + { + if(!core) + throw Internal_Error("Power_Mod::execute: core was NULL"); + return core->execute(); + } + +/* +* Try to choose a good window size +*/ +size_t Power_Mod::window_bits(size_t exp_bits, size_t, + Power_Mod::Usage_Hints hints) + { + static const size_t wsize[][2] = { + { 1434, 7 }, + { 539, 6 }, + { 197, 4 }, + { 70, 3 }, + { 25, 2 }, + { 0, 0 } + }; + + size_t window_bits = 1; + + if(exp_bits) + { + for(size_t j = 0; wsize[j][0]; ++j) + { + if(exp_bits >= wsize[j][0]) + { + window_bits += wsize[j][1]; + break; + } + } + } + + if(hints & Power_Mod::BASE_IS_FIXED) + window_bits += 2; + if(hints & Power_Mod::EXP_IS_LARGE) + ++window_bits; + + return window_bits; + } + +namespace { + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_base_hints(const BigInt& b, const BigInt& n) + { + if(b == 2) + return Power_Mod::Usage_Hints(Power_Mod::BASE_IS_2 | + Power_Mod::BASE_IS_SMALL); + + const size_t b_bits = b.bits(); + const size_t n_bits = n.bits(); + + if(b_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(b_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + + return Power_Mod::NO_HINTS; + } + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_exp_hints(const BigInt& e, const BigInt& n) + { + const size_t e_bits = e.bits(); + const size_t n_bits = n.bits(); + + if(e_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(e_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + return Power_Mod::NO_HINTS; + } + +} + +/* +* Fixed_Exponent_Power_Mod Constructor +*/ +Fixed_Exponent_Power_Mod::Fixed_Exponent_Power_Mod(const BigInt& e, + const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | EXP_IS_FIXED | choose_exp_hints(e, n))) + { + set_exponent(e); + } + +/* +* Fixed_Base_Power_Mod Constructor +*/ +Fixed_Base_Power_Mod::Fixed_Base_Power_Mod(const BigInt& b, const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | BASE_IS_FIXED | choose_base_hints(b, n))) + { + set_base(b); + } + +} diff --git a/src/lib/math/numbertheory/pow_mod.h b/src/lib/math/numbertheory/pow_mod.h new file mode 100644 index 000000000..b78510793 --- /dev/null +++ b/src/lib/math/numbertheory/pow_mod.h @@ -0,0 +1,104 @@ +/* +* Modular Exponentiator +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_POWER_MOD_H__ +#define BOTAN_POWER_MOD_H__ + +#include + +namespace Botan { + +/** +* Modular Exponentiator Interface +*/ +class BOTAN_DLL Modular_Exponentiator + { + public: + virtual void set_base(const BigInt&) = 0; + virtual void set_exponent(const BigInt&) = 0; + virtual BigInt execute() const = 0; + virtual Modular_Exponentiator* copy() const = 0; + virtual ~Modular_Exponentiator() {} + }; + +/** +* Modular Exponentiator Proxy +*/ +class BOTAN_DLL Power_Mod + { + public: + + enum Usage_Hints { + NO_HINTS = 0x0000, + + BASE_IS_FIXED = 0x0001, + BASE_IS_SMALL = 0x0002, + BASE_IS_LARGE = 0x0004, + BASE_IS_2 = 0x0008, + + EXP_IS_FIXED = 0x0100, + EXP_IS_SMALL = 0x0200, + EXP_IS_LARGE = 0x0400 + }; + + /* + * Try to choose a good window size + */ + static size_t window_bits(size_t exp_bits, size_t base_bits, + Power_Mod::Usage_Hints hints); + + void set_modulus(const BigInt&, Usage_Hints = NO_HINTS) const; + void set_base(const BigInt&) const; + void set_exponent(const BigInt&) const; + + BigInt execute() const; + + Power_Mod& operator=(const Power_Mod&); + + Power_Mod(const BigInt& = 0, Usage_Hints = NO_HINTS); + Power_Mod(const Power_Mod&); + virtual ~Power_Mod(); + private: + mutable Modular_Exponentiator* core; + Usage_Hints hints; + }; + +/** +* Fixed Exponent Modular Exponentiator Proxy +*/ +class BOTAN_DLL Fixed_Exponent_Power_Mod : public Power_Mod + { + public: + BigInt operator()(const BigInt& b) const + { set_base(b); return execute(); } + + Fixed_Exponent_Power_Mod() {} + + Fixed_Exponent_Power_Mod(const BigInt& exponent, + const BigInt& modulus, + Usage_Hints hints = NO_HINTS); + }; + +/** +* Fixed Base Modular Exponentiator Proxy +*/ +class BOTAN_DLL Fixed_Base_Power_Mod : public Power_Mod + { + public: + BigInt operator()(const BigInt& e) const + { set_exponent(e); return execute(); } + + Fixed_Base_Power_Mod() {} + + Fixed_Base_Power_Mod(const BigInt& base, + const BigInt& modulus, + Usage_Hints hints = NO_HINTS); + }; + +} + +#endif diff --git a/src/lib/math/numbertheory/powm_fw.cpp b/src/lib/math/numbertheory/powm_fw.cpp new file mode 100644 index 000000000..16a48a5b0 --- /dev/null +++ b/src/lib/math/numbertheory/powm_fw.cpp @@ -0,0 +1,69 @@ +/* +* Fixed Window Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Set the exponent +*/ +void Fixed_Window_Exponentiator::set_exponent(const BigInt& e) + { + exp = e; + } + +/* +* Set the base +*/ +void Fixed_Window_Exponentiator::set_base(const BigInt& base) + { + window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints); + + g.resize((1 << window_bits)); + g[0] = 1; + g[1] = base; + + for(size_t i = 2; i != g.size(); ++i) + g[i] = reducer.multiply(g[i-1], g[0]); + } + +/* +* Compute the result +*/ +BigInt Fixed_Window_Exponentiator::execute() const + { + const size_t exp_nibbles = (exp.bits() + window_bits - 1) / window_bits; + + BigInt x = 1; + + for(size_t i = exp_nibbles; i > 0; --i) + { + for(size_t j = 0; j != window_bits; ++j) + x = reducer.square(x); + + const u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits); + + x = reducer.multiply(x, g[nibble]); + } + return x; + } + +/* +* Fixed_Window_Exponentiator Constructor +*/ +Fixed_Window_Exponentiator::Fixed_Window_Exponentiator(const BigInt& n, + Power_Mod::Usage_Hints hints) + { + reducer = Modular_Reducer(n); + this->hints = hints; + window_bits = 0; + } + +} diff --git a/src/lib/math/numbertheory/powm_mnt.cpp b/src/lib/math/numbertheory/powm_mnt.cpp new file mode 100644 index 000000000..a3eac1f83 --- /dev/null +++ b/src/lib/math/numbertheory/powm_mnt.cpp @@ -0,0 +1,142 @@ +/* +* Montgomery Exponentiation +* (C) 1999-2010,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Set the exponent +*/ +void Montgomery_Exponentiator::set_exponent(const BigInt& exp) + { + m_exp = exp; + m_exp_bits = exp.bits(); + } + +/* +* Set the base +*/ +void Montgomery_Exponentiator::set_base(const BigInt& base) + { + m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints); + + m_g.resize((1 << m_window_bits)); + + BigInt z(BigInt::Positive, 2 * (m_mod_words + 1)); + secure_vector workspace(z.size()); + + m_g[0] = 1; + + bigint_monty_mul(z.mutable_data(), z.size(), + m_g[0].data(), m_g[0].size(), m_g[0].sig_words(), + m_R2_mod.data(), m_R2_mod.size(), m_R2_mod.sig_words(), + m_modulus.data(), m_mod_words, m_mod_prime, + &workspace[0]); + + m_g[0] = z; + + m_g[1] = (base >= m_modulus) ? (base % m_modulus) : base; + + bigint_monty_mul(z.mutable_data(), z.size(), + m_g[1].data(), m_g[1].size(), m_g[1].sig_words(), + m_R2_mod.data(), m_R2_mod.size(), m_R2_mod.sig_words(), + m_modulus.data(), m_mod_words, m_mod_prime, + &workspace[0]); + + m_g[1] = z; + + const BigInt& x = m_g[1]; + const size_t x_sig = x.sig_words(); + + for(size_t i = 2; i != m_g.size(); ++i) + { + const BigInt& y = m_g[i-1]; + const size_t y_sig = y.sig_words(); + + bigint_monty_mul(z.mutable_data(), z.size(), + x.data(), x.size(), x_sig, + y.data(), y.size(), y_sig, + m_modulus.data(), m_mod_words, m_mod_prime, + &workspace[0]); + + m_g[i] = z; + } + } + +/* +* Compute the result +*/ +BigInt Montgomery_Exponentiator::execute() const + { + const size_t exp_nibbles = (m_exp_bits + m_window_bits - 1) / m_window_bits; + + BigInt x = m_R_mod; + + const size_t z_size = 2*(m_mod_words + 1); + + BigInt z(BigInt::Positive, z_size); + secure_vector workspace(z_size); + + for(size_t i = exp_nibbles; i > 0; --i) + { + for(size_t k = 0; k != m_window_bits; ++k) + { + bigint_monty_sqr(z.mutable_data(), z_size, + x.data(), x.size(), x.sig_words(), + m_modulus.data(), m_mod_words, m_mod_prime, + &workspace[0]); + + x = z; + } + + const u32bit nibble = m_exp.get_substring(m_window_bits*(i-1), m_window_bits); + + const BigInt& y = m_g[nibble]; + + bigint_monty_mul(z.mutable_data(), z_size, + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + m_modulus.data(), m_mod_words, m_mod_prime, + &workspace[0]); + + x = z; + } + + x.grow_to(2*m_mod_words + 1); + + bigint_monty_redc(x.mutable_data(), + m_modulus.data(), m_mod_words, m_mod_prime, + &workspace[0]); + + return x; + } + +/* +* Montgomery_Exponentiator Constructor +*/ +Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, + Power_Mod::Usage_Hints hints) : + m_modulus(mod), + m_mod_words(m_modulus.sig_words()), + m_window_bits(1), + m_hints(hints) + { + // Montgomery reduction only works for positive odd moduli + if(!m_modulus.is_positive() || m_modulus.is_even()) + throw Invalid_Argument("Montgomery_Exponentiator: invalid modulus"); + + m_mod_prime = monty_inverse(mod.word_at(0)); + + const BigInt r = BigInt::power_of_2(m_mod_words * BOTAN_MP_WORD_BITS); + m_R_mod = r % m_modulus; + m_R2_mod = (m_R_mod * m_R_mod) % m_modulus; + } + +} diff --git a/src/lib/math/numbertheory/primes.cpp b/src/lib/math/numbertheory/primes.cpp new file mode 100644 index 000000000..a0c0f0093 --- /dev/null +++ b/src/lib/math/numbertheory/primes.cpp @@ -0,0 +1,609 @@ +/* +* Small Primes Table +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const u16bit PRIMES[PRIME_TABLE_SIZE+1] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, + 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, + 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, + 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, + 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, + 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, + 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, + 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, + 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, + 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, + 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, + 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, + 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, + 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, + 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, + 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, + 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, + 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, + 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, + 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, + 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, + 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, + 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, + 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, + 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, + 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, + 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, + 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, + 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, + 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, + 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, + 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, + 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, + 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, + 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, + 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, + 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, + 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, + 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, + 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, + 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, + 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, + 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, + 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, + 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, + 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, + 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, + 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, + 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, + 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, + 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, + 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, + 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, + 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, + 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, + 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, + 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, + 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, + 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, + 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, + 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, + 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, + 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, + 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, + 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, + 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, + 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, + 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, + 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, + 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, + 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, + 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, + 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, + 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, + 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, + 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, + 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, + 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, + 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, + 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, + 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, + 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, + 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, +10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, +10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, +10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, +10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, +10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, +10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, +10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, +10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, +10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, +10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, +11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, +11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, +11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, +11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, +11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, +11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, +11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, +11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, +11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, +12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, +12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, +12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, +12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, +12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, +12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, +12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, +12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, +12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, +12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, +13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, +13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, +13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, +13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, +13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, +13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, +13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, +13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, +13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, +13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, +14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, +14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, +14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, +14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, +14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, +14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, +14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, +14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, +14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, +15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, +15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, +15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, +15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, +15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, +15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, +15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, +15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, +15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, +15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, +16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, +16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, +16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, +16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, +16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, +16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, +16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, +16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, +16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, +17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, +17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, +17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, +17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, +17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, +17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, +17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, +17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, +17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, +18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, +18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, +18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, +18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, +18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, +18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, +18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, +18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, +18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, +19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, +19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, +19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, +19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, +19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, +19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, +19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, +19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, +19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, +20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, +20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, +20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, +20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, +20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, +20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, +20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, +20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, +20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, +21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, +21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, +21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, +21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, +21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, +21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, +21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, +21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, +21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, +22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, +22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, +22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, +22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, +22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, +22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, +22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, +22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, +22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, +23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, +23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, +23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, +23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, +23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, +23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, +23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, +23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, +23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, +23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, +24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, +24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, +24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, +24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, +24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, +24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, +24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, +24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, +25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, +25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, +25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, +25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, +25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, +25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, +25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, +25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, +25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, +26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, +26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, +26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, +26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, +26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, +26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, +26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, +26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, +26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, +26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, +27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, +27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, +27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, +27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, +27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, +27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, +27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, +27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, +28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, +28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, +28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, +28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, +28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, +28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, +28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, +28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, +28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, +29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, +29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, +29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, +29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, +29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, +29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, +29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, +29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, +30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, +30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, +30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, +30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, +30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, +30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, +30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, +30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, +30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, +31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, +31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, +31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, +31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, +31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, +31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, +31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, +31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, +32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, +32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, +32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, +32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, +32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, +32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, +32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, +32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, +32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, +32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, +33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, +33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, +33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, +33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, +33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, +33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, +33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, +33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, +33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, +34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, +34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, +34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, +34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, +34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, +34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, +34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, +34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, +34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, +35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, +35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, +35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, +35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, +35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, +35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, +35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, +35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, +36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, +36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, +36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, +36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, +36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, +36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, +36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, +36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, +36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, +37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, +37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, +37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, +37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, +37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, +37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, +37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, +37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, +37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, +38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, +38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, +38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, +38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, +38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, +38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, +38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, +38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, +39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, +39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, +39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, +39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, +39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, +39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, +39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, +39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, +40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, +40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, +40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, +40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, +40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, +40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, +40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, +40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, +41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, +41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, +41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, +41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, +41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, +41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, +41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, +41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, +41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, +41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, +42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, +42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, +42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, +42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, +42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, +42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, +42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, +42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, +42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, +43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, +43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, +43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, +43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, +43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, +43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, +43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, +43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, +44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, +44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, +44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, +44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, +44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, +44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, +44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, +44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, +45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, +45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, +45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, +45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, +45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, +45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, +45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, +45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, +46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, +46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, +46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, +46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, +46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, +46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, +46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, +46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, +47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, +47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, +47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, +47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, +47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, +47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, +47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, +47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, +47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, +48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, +48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, +48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, +48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, +48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, +48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, +48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, +48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, +49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, +49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, +49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, +49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, +49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, +49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, +49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, +49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, +49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, +50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, +50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, +50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, +50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, +50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, +50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, +50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, +50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, +51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, +51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, +51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, +51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, +51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, +51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, +51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, +51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, +51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, +52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, +52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, +52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, +52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, +52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, +52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, +52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, +52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, +53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, +53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, +53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, +53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, +53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, +53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, +53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, +53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, +54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, +54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, +54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, +54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, +54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, +54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, +54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, +54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, +54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, +55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, +55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, +55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, +55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, +55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, +55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, +55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, +55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, +56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, +56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, +56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, +56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, +56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, +56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, +56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, +56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, +56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, +57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, +57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, +57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, +57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, +57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, +57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, +57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, +57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, +58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, +58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, +58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, +58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, +58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, +58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, +58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, +58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, +59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, +59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, +59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, +59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, +59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, +59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, +59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, +59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, +59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, +60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, +60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, +60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, +60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, +60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, +60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, +60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, +60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, +61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, +61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, +61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, +61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, +61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, +61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, +61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, +61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, +62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, +62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, +62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, +62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, +62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, +62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, +62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, +62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, +63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, +63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, +63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, +63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, +63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, +63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, +63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, +63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, +64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, +64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, +64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, +64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, +64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, +64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, +64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, +64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, +65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, +65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, +65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, +65437, 65447, 65449, 65479, 65497, 65519, 65521, 0 }; + +} diff --git a/src/lib/math/numbertheory/reducer.cpp b/src/lib/math/numbertheory/reducer.cpp new file mode 100644 index 000000000..8e8951c46 --- /dev/null +++ b/src/lib/math/numbertheory/reducer.cpp @@ -0,0 +1,81 @@ +/* +* Modular Reducer +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Modular_Reducer Constructor +*/ +Modular_Reducer::Modular_Reducer(const BigInt& mod) + { + if(mod <= 0) + throw Invalid_Argument("Modular_Reducer: modulus must be positive"); + + modulus = mod; + mod_words = modulus.sig_words(); + + modulus_2 = Botan::square(modulus); + + mu = BigInt::power_of_2(2 * MP_WORD_BITS * mod_words) / modulus; + } + +/* +* Barrett Reduction +*/ +BigInt Modular_Reducer::reduce(const BigInt& x) const + { + if(mod_words == 0) + throw Invalid_State("Modular_Reducer: Never initalized"); + + if(x.cmp(modulus, false) < 0) + { + if(x.is_negative()) + return x + modulus; // make positive + return x; + } + else if(x.cmp(modulus_2, false) < 0) + { + BigInt t1 = x; + t1.set_sign(BigInt::Positive); + t1 >>= (MP_WORD_BITS * (mod_words - 1)); + t1 *= mu; + + t1 >>= (MP_WORD_BITS * (mod_words + 1)); + t1 *= modulus; + + t1.mask_bits(MP_WORD_BITS * (mod_words + 1)); + + BigInt t2 = x; + t2.set_sign(BigInt::Positive); + t2.mask_bits(MP_WORD_BITS * (mod_words + 1)); + + t2 -= t1; + + if(t2.is_negative()) + { + t2 += BigInt::power_of_2(MP_WORD_BITS * (mod_words + 1)); + } + + while(t2 >= modulus) + t2 -= modulus; + + if(x.is_positive()) + return t2; + else + return (modulus - t2); + } + else + { + // too big, fall back to normal division + return (x % modulus); + } + } + +} diff --git a/src/lib/math/numbertheory/reducer.h b/src/lib/math/numbertheory/reducer.h new file mode 100644 index 000000000..76712074c --- /dev/null +++ b/src/lib/math/numbertheory/reducer.h @@ -0,0 +1,61 @@ +/* +* Modular Reducer +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODULAR_REDUCER_H__ +#define BOTAN_MODULAR_REDUCER_H__ + +#include + +namespace Botan { + +/** +* Modular Reducer (using Barrett's technique) +*/ +class BOTAN_DLL Modular_Reducer + { + public: + const BigInt& get_modulus() const { return modulus; } + + BigInt reduce(const BigInt& x) const; + + /** + * Multiply mod p + * @param x + * @param y + * @return (x * y) % p + */ + BigInt multiply(const BigInt& x, const BigInt& y) const + { return reduce(x * y); } + + /** + * Square mod p + * @param x + * @return (x * x) % p + */ + BigInt square(const BigInt& x) const + { return reduce(Botan::square(x)); } + + /** + * Cube mod p + * @param x + * @return (x * x * x) % p + */ + BigInt cube(const BigInt& x) const + { return multiply(x, this->square(x)); } + + bool initialized() const { return (mod_words != 0); } + + Modular_Reducer() { mod_words = 0; } + Modular_Reducer(const BigInt& mod); + private: + BigInt modulus, modulus_2, mu; + size_t mod_words; + }; + +} + +#endif diff --git a/src/lib/math/numbertheory/ressol.cpp b/src/lib/math/numbertheory/ressol.cpp new file mode 100644 index 000000000..9c48187f4 --- /dev/null +++ b/src/lib/math/numbertheory/ressol.cpp @@ -0,0 +1,81 @@ +/* +* Shanks-Tonnelli (RESSOL) +* (C) 2007-2008 Falko Strenzke, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Shanks-Tonnelli algorithm +*/ +BigInt ressol(const BigInt& a, const BigInt& p) + { + if(a < 0) + throw Invalid_Argument("ressol(): a to solve for must be positive"); + if(p <= 1) + throw Invalid_Argument("ressol(): prime must be > 1"); + + if(a == 0) + return 0; + if(p == 2) + return a; + + if(jacobi(a, p) != 1) // not a quadratic residue + return -BigInt(1); + + if(p % 4 == 3) + return power_mod(a, ((p+1) >> 2), p); + + size_t s = low_zero_bits(p - 1); + BigInt q = p >> s; + + q -= 1; + q >>= 1; + + Modular_Reducer mod_p(p); + + BigInt r = power_mod(a, q, p); + BigInt n = mod_p.multiply(a, mod_p.square(r)); + r = mod_p.multiply(r, a); + + if(n == 1) + return r; + + // find random non quadratic residue z + BigInt z = 2; + while(jacobi(z, p) == 1) // while z quadratic residue + ++z; + + BigInt c = power_mod(z, (q << 1) + 1, p); + + while(n > 1) + { + q = n; + + size_t i = 0; + while(q != 1) + { + q = mod_p.square(q); + ++i; + } + + if(s <= i) + return -BigInt(1); + + c = power_mod(c, BigInt::power_of_2(s-i-1), p); + r = mod_p.multiply(r, c); + c = mod_p.square(c); + n = mod_p.multiply(n, c); + s = i; + } + + return r; + } + +} diff --git a/src/lib/modes/aead/aead.cpp b/src/lib/modes/aead/aead.cpp new file mode 100644 index 000000000..da860c26a --- /dev/null +++ b/src/lib/modes/aead/aead.cpp @@ -0,0 +1,122 @@ +/* +* Interface for AEAD modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if defined(BOTAN_HAS_AEAD_CCM) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_SIV) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + #include +#endif + +namespace Botan { + +AEAD_Mode* get_aead(const std::string& algo_spec, Cipher_Dir direction) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + const std::vector algo_parts = split_on(algo_spec, '/'); + if(algo_parts.empty()) + throw Invalid_Algorithm_Name(algo_spec); + + if(algo_parts.size() < 2) + return nullptr; + + const std::string cipher_name = algo_parts[0]; + const BlockCipher* cipher = af.prototype_block_cipher(cipher_name); + if(!cipher) + return nullptr; + + const std::vector mode_info = parse_algorithm_name(algo_parts[1]); + + if(mode_info.empty()) + return nullptr; + + const std::string mode_name = mode_info[0]; + + const size_t tag_size = (mode_info.size() > 1) ? to_u32bit(mode_info[1]) : cipher->block_size(); + +#if defined(BOTAN_HAS_AEAD_CCM) + if(mode_name == "CCM-8") + { + if(direction == ENCRYPTION) + return new CCM_Encryption(cipher->clone(), 8, 3); + else + return new CCM_Decryption(cipher->clone(), 8, 3); + } + + if(mode_name == "CCM" || mode_name == "CCM-8") + { + const size_t L = (mode_info.size() > 2) ? to_u32bit(mode_info[2]) : 3; + + if(direction == ENCRYPTION) + return new CCM_Encryption(cipher->clone(), tag_size, L); + else + return new CCM_Decryption(cipher->clone(), tag_size, L); + } +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + if(mode_name == "EAX") + { + if(direction == ENCRYPTION) + return new EAX_Encryption(cipher->clone(), tag_size); + else + return new EAX_Decryption(cipher->clone(), tag_size); + } +#endif + +#if defined(BOTAN_HAS_AEAD_SIV) + if(mode_name == "SIV") + { + BOTAN_ASSERT(tag_size == 16, "Valid tag size for SIV"); + if(direction == ENCRYPTION) + return new SIV_Encryption(cipher->clone()); + else + return new SIV_Decryption(cipher->clone()); + } +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + if(mode_name == "GCM") + { + if(direction == ENCRYPTION) + return new GCM_Encryption(cipher->clone(), tag_size); + else + return new GCM_Decryption(cipher->clone(), tag_size); + } +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + if(mode_name == "OCB") + { + if(direction == ENCRYPTION) + return new OCB_Encryption(cipher->clone(), tag_size); + else + return new OCB_Decryption(cipher->clone(), tag_size); + } +#endif + + return nullptr; + } + +} diff --git a/src/lib/modes/aead/aead.h b/src/lib/modes/aead/aead.h new file mode 100644 index 000000000..8df98fcad --- /dev/null +++ b/src/lib/modes/aead/aead.h @@ -0,0 +1,66 @@ +/* +* Interface for AEAD modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_MODE_H__ +#define BOTAN_AEAD_MODE_H__ + +#include + +namespace Botan { + +/** +* Interface for AEAD (Authenticated Encryption with Associated Data) +* modes. These modes provide both encryption and message +* authentication, and can authenticate additional per-message data +* which is not included in the ciphertext (for instance a sequence +* number). +*/ +class BOTAN_DLL AEAD_Mode : public Cipher_Mode + { + public: + bool authenticated() const override { return true; } + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key + * and before finish. + * + * Unless reset by another call, the associated data is kept + * between messages. Thus, if the AD does not change, calling + * once (after set_key) is the optimum. + * + * @param ad the associated data + * @param ad_len length of add in bytes + */ + virtual void set_associated_data(const byte ad[], size_t ad_len) = 0; + + template + void set_associated_data_vec(const std::vector& ad) + { + set_associated_data(&ad[0], ad.size()); + } + + /** + * Default AEAD nonce size (a commonly supported value among AEAD + * modes, and large enough that random collisions are unlikely). + */ + size_t default_nonce_length() const override { return 12; } + + /** + * Return the size of the authentication tag used (in bytes) + */ + virtual size_t tag_size() const = 0; + }; + +/** +* Get an AEAD mode by name (eg "AES-128/GCM" or "Serpent/EAX") +*/ +BOTAN_DLL AEAD_Mode* get_aead(const std::string& name, Cipher_Dir direction); + +} + +#endif diff --git a/src/lib/modes/aead/ccm/ccm.cpp b/src/lib/modes/aead/ccm/ccm.cpp new file mode 100644 index 000000000..50fc38738 --- /dev/null +++ b/src/lib/modes/aead/ccm/ccm.cpp @@ -0,0 +1,266 @@ +/* +* CCM Mode Encryption +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* CCM_Mode Constructor +*/ +CCM_Mode::CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L) : + m_tag_size(tag_size), + m_L(L), + m_cipher(cipher) + { + if(m_cipher->block_size() != BS) + throw std::invalid_argument(m_cipher->name() + " cannot be used with CCM mode"); + + if(L < 2 || L > 8) + throw std::invalid_argument("Invalid CCM L value " + std::to_string(L)); + + if(tag_size < 4 || tag_size > 16 || tag_size % 2 != 0) + throw std::invalid_argument("invalid CCM tag length " + std::to_string(tag_size)); + } + +void CCM_Mode::clear() + { + m_cipher.reset(); + m_msg_buf.clear(); + m_ad_buf.clear(); + } + +std::string CCM_Mode::name() const + { + return (m_cipher->name() + "/CCM(" + std::to_string(tag_size()) + "," + std::to_string(L())) + ")"; + } + +bool CCM_Mode::valid_nonce_length(size_t n) const + { + return (n == (15-L())); + } + +size_t CCM_Mode::default_nonce_length() const + { + return (15-L()); + } + +size_t CCM_Mode::update_granularity() const + { + /* + This value does not particularly matter as regardless CCM_Mode::update + buffers all input, so in theory this could be 1. However as for instance + Transformation_Filter creates update_granularity() byte buffers, use a + somewhat large size to avoid bouncing on a tiny buffer. + */ + return m_cipher->parallel_bytes(); + } + +Key_Length_Specification CCM_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +void CCM_Mode::key_schedule(const byte key[], size_t length) + { + m_cipher->set_key(key, length); + } + +void CCM_Mode::set_associated_data(const byte ad[], size_t length) + { + m_ad_buf.clear(); + + if(length) + { + // FIXME: support larger AD using length encoding rules + BOTAN_ASSERT(length < (0xFFFF - 0xFF), "Supported CCM AD length"); + + m_ad_buf.push_back(get_byte(0, length)); + m_ad_buf.push_back(get_byte(1, length)); + m_ad_buf += std::make_pair(ad, length); + while(m_ad_buf.size() % BS) + m_ad_buf.push_back(0); // pad with zeros to full block size + } + } + +secure_vector CCM_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_nonce.assign(nonce, nonce + nonce_len); + m_msg_buf.clear(); + + return secure_vector(); + } + +void CCM_Mode::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz); + buffer.resize(offset); // truncate msg + } + +void CCM_Mode::encode_length(size_t len, byte out[]) + { + const size_t len_bytes = L(); + + BOTAN_ASSERT(len_bytes < sizeof(size_t), "Length field fits"); + + for(size_t i = 0; i != len_bytes; ++i) + out[i] = get_byte(sizeof(size_t)-i, len); + + BOTAN_ASSERT((len >> (len_bytes*8)) == 0, "Message length fits in field"); + } + +void CCM_Mode::inc(secure_vector& C) + { + for(size_t i = 0; i != C.size(); ++i) + if(++C[C.size()-i-1]) + break; + } + +secure_vector CCM_Mode::format_b0(size_t sz) + { + secure_vector B0(BS); + + const byte b_flags = (m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1); + + B0[0] = b_flags; + copy_mem(&B0[1], &m_nonce[0], m_nonce.size()); + encode_length(sz, &B0[m_nonce.size()+1]); + + return B0; + } + +secure_vector CCM_Mode::format_c0() + { + secure_vector C(BS); + + const byte a_flags = L()-1; + + C[0] = a_flags; + copy_mem(&C[1], &m_nonce[0], m_nonce.size()); + + return C; + } + +void CCM_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const secure_vector& ad = ad_buf(); + BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple"); + + const BlockCipher& E = cipher(); + + secure_vector T(BS); + E.encrypt(format_b0(sz), T); + + for(size_t i = 0; i != ad.size(); i += BS) + { + xor_buf(&T[0], &ad[i], BS); + E.encrypt(T); + } + + secure_vector C = format_c0(); + secure_vector S0(BS); + E.encrypt(C, S0); + inc(C); + + secure_vector X(BS); + + const byte* buf_end = &buf[sz]; + + while(buf != buf_end) + { + const size_t to_proc = std::min(BS, buf_end - buf); + + xor_buf(&T[0], buf, to_proc); + E.encrypt(T); + + E.encrypt(C, X); + xor_buf(buf, &X[0], to_proc); + inc(C); + + buf += to_proc; + } + + T ^= S0; + + buffer += std::make_pair(&T[0], tag_size()); + } + +void CCM_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); + + const secure_vector& ad = ad_buf(); + BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple"); + + const BlockCipher& E = cipher(); + + secure_vector T(BS); + E.encrypt(format_b0(sz - tag_size()), T); + + for(size_t i = 0; i != ad.size(); i += BS) + { + xor_buf(&T[0], &ad[i], BS); + E.encrypt(T); + } + + secure_vector C = format_c0(); + + secure_vector S0(BS); + E.encrypt(C, S0); + inc(C); + + secure_vector X(BS); + + const byte* buf_end = &buf[sz - tag_size()]; + + while(buf != buf_end) + { + const size_t to_proc = std::min(BS, buf_end - buf); + + E.encrypt(C, X); + xor_buf(buf, &X[0], to_proc); + inc(C); + + xor_buf(&T[0], buf, to_proc); + E.encrypt(T); + + buf += to_proc; + } + + T ^= S0; + + if(!same_mem(&T[0], buf_end, tag_size())) + throw Integrity_Failure("CCM tag check failed"); + + buffer.resize(buffer.size() - tag_size()); + } + +} diff --git a/src/lib/modes/aead/ccm/ccm.h b/src/lib/modes/aead/ccm/ccm.h new file mode 100644 index 000000000..87dd5805c --- /dev/null +++ b/src/lib/modes/aead/ccm/ccm.h @@ -0,0 +1,128 @@ +/* +* CCM Mode +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_CCM_H__ +#define BOTAN_AEAD_CCM_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Base class for CCM encryption and decryption +* @see RFC 3610 +*/ +class BOTAN_DLL CCM_Mode : public AEAD_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + void update(secure_vector& blocks, size_t offset = 0) override; + + void set_associated_data(const byte ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t) const override; + + size_t default_nonce_length() const override; + + void clear(); + + size_t tag_size() const { return m_tag_size; } + + protected: + const size_t BS = 16; // intrinsic to CCM definition + + CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L); + + size_t L() const { return m_L; } + + const BlockCipher& cipher() const { return *m_cipher; } + + void encode_length(size_t len, byte out[]); + + void inc(secure_vector& C); + + const secure_vector& ad_buf() const { return m_ad_buf; } + + secure_vector& msg_buf() { return m_msg_buf; } + + secure_vector format_b0(size_t msg_size); + secure_vector format_c0(); + private: + void key_schedule(const byte key[], size_t length) override; + + const size_t m_tag_size; + const size_t m_L; + + std::unique_ptr m_cipher; + secure_vector m_nonce, m_msg_buf, m_ad_buf; + }; + +/** +* CCM Encryption +*/ +class BOTAN_DLL CCM_Encryption : public CCM_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be (even values + * between 4 and 16 are accepted) + * @param L length of L parameter. The total message length + * must be less than 2**L bytes, and the nonce is 15-L bytes. + */ + CCM_Encryption(BlockCipher* cipher, size_t tag_size = 16, size_t L = 3) : + CCM_Mode(cipher, tag_size, L) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + }; + +/** +* CCM Decryption +*/ +class BOTAN_DLL CCM_Decryption : public CCM_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be (even values + * between 4 and 16 are accepted) + * @param L length of L parameter. The total message length + * must be less than 2**L bytes, and the nonce is 15-L bytes. + */ + CCM_Decryption(BlockCipher* cipher, size_t tag_size = 16, size_t L = 3) : + CCM_Mode(cipher, tag_size, L) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + }; + +} + +#endif diff --git a/src/lib/modes/aead/ccm/info.txt b/src/lib/modes/aead/ccm/info.txt new file mode 100644 index 000000000..ee8373caf --- /dev/null +++ b/src/lib/modes/aead/ccm/info.txt @@ -0,0 +1 @@ +define AEAD_CCM 20131128 diff --git a/src/lib/modes/aead/eax/eax.cpp b/src/lib/modes/aead/eax/eax.cpp new file mode 100644 index 000000000..249bf5f7e --- /dev/null +++ b/src/lib/modes/aead/eax/eax.cpp @@ -0,0 +1,170 @@ +/* +* EAX Mode Encryption +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* EAX MAC-based PRF +*/ +secure_vector eax_prf(byte tag, size_t block_size, + MessageAuthenticationCode& mac, + const byte in[], size_t length) + { + for(size_t i = 0; i != block_size - 1; ++i) + mac.update(0); + mac.update(tag); + mac.update(in, length); + return mac.final(); + } + +} + +/* +* EAX_Mode Constructor +*/ +EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) : + m_tag_size(tag_size ? tag_size : cipher->block_size()), + m_cipher(cipher), + m_ctr(new CTR_BE(m_cipher->clone())), + m_cmac(new CMAC(m_cipher->clone())) + { + if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) + throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size)); + } + +void EAX_Mode::clear() + { + m_cipher.reset(); + m_ctr.reset(); + m_cmac.reset(); + zeroise(m_ad_mac); + zeroise(m_nonce_mac); + } + +std::string EAX_Mode::name() const + { + return (m_cipher->name() + "/EAX"); + } + +size_t EAX_Mode::update_granularity() const + { + return 8 * m_cipher->parallel_bytes(); + } + +Key_Length_Specification EAX_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +/* +* Set the EAX key +*/ +void EAX_Mode::key_schedule(const byte key[], size_t length) + { + /* + * These could share the key schedule, which is one nice part of EAX, + * but it's much easier to ignore that here... + */ + m_ctr->set_key(key, length); + m_cmac->set_key(key, length); + + m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); + } + +/* +* Set the EAX associated data +*/ +void EAX_Mode::set_associated_data(const byte ad[], size_t length) + { + m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length); + } + +secure_vector EAX_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len); + + m_ctr->set_iv(&m_nonce_mac[0], m_nonce_mac.size()); + + for(size_t i = 0; i != block_size() - 1; ++i) + m_cmac->update(0); + m_cmac->update(2); + + return secure_vector(); + } + +void EAX_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + m_ctr->cipher(buf, buf, sz); + m_cmac->update(buf, sz); + } + +void EAX_Encryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + + secure_vector data_mac = m_cmac->final(); + xor_buf(data_mac, m_nonce_mac, data_mac.size()); + xor_buf(data_mac, m_ad_mac, data_mac.size()); + + buffer += std::make_pair(&data_mac[0], tag_size()); + } + +void EAX_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + m_cmac->update(buf, sz); + m_ctr->cipher(buf, buf, sz); + } + +void EAX_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); + + const size_t remaining = sz - tag_size(); + + if(remaining) + { + m_cmac->update(buf, remaining); + m_ctr->cipher(buf, buf, remaining); + } + + const byte* included_tag = &buf[remaining]; + + secure_vector mac = m_cmac->final(); + mac ^= m_nonce_mac; + mac ^= m_ad_mac; + + if(!same_mem(&mac[0], included_tag, tag_size())) + throw Integrity_Failure("EAX tag check failed"); + + buffer.resize(offset + remaining); + } + +} diff --git a/src/lib/modes/aead/eax/eax.h b/src/lib/modes/aead/eax/eax.h new file mode 100644 index 000000000..224fb5298 --- /dev/null +++ b/src/lib/modes/aead/eax/eax.h @@ -0,0 +1,114 @@ +/* +* EAX Mode +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_EAX_H__ +#define BOTAN_AEAD_EAX_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* EAX base class +*/ +class BOTAN_DLL EAX_Mode : public AEAD_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + void set_associated_data(const byte ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + // EAX supports arbitrary nonce lengths + bool valid_nonce_length(size_t) const override { return true; } + + size_t tag_size() const { return m_tag_size; } + + void clear(); + protected: + void key_schedule(const byte key[], size_t length) override; + + /** + * @param cipher the cipher to use + * @param tag_size is how big the auth tag will be + */ + EAX_Mode(BlockCipher* cipher, size_t tag_size); + + size_t block_size() const { return m_cipher->block_size(); } + + size_t m_tag_size; + + std::unique_ptr m_cipher; + std::unique_ptr m_ctr; + std::unique_ptr m_cmac; + + secure_vector m_ad_mac; + + secure_vector m_nonce_mac; + }; + +/** +* EAX Encryption +*/ +class BOTAN_DLL EAX_Encryption : public EAX_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be + */ + EAX_Encryption(BlockCipher* cipher, size_t tag_size = 0) : + EAX_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* EAX Decryption +*/ +class BOTAN_DLL EAX_Decryption : public EAX_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be + */ + EAX_Decryption(BlockCipher* cipher, size_t tag_size = 0) : + EAX_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/src/lib/modes/aead/eax/info.txt b/src/lib/modes/aead/eax/info.txt new file mode 100644 index 000000000..75775fa16 --- /dev/null +++ b/src/lib/modes/aead/eax/info.txt @@ -0,0 +1,7 @@ +define AEAD_EAX 20131128 + + +block +cmac +ctr + diff --git a/src/lib/modes/aead/gcm/clmul/clmul.cpp b/src/lib/modes/aead/gcm/clmul/clmul.cpp new file mode 100644 index 000000000..cc6d581e3 --- /dev/null +++ b/src/lib/modes/aead/gcm/clmul/clmul.cpp @@ -0,0 +1,76 @@ +/* +* CLMUL hook +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +void gcm_multiply_clmul(byte x[16], const byte H[16]) + { + /* + * Algorithms 1 and 5 from Intel's CLMUL guide + */ + const __m128i BSWAP_MASK = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + + __m128i a = _mm_loadu_si128(reinterpret_cast(&x[0])); + __m128i b = _mm_loadu_si128(reinterpret_cast(&H[0])); + + a = _mm_shuffle_epi8(a, BSWAP_MASK); + b = _mm_shuffle_epi8(b, BSWAP_MASK); + + __m128i T0, T1, T2, T3, T4, T5; + + T0 = _mm_clmulepi64_si128(a, b, 0x00); + T1 = _mm_clmulepi64_si128(a, b, 0x01); + T2 = _mm_clmulepi64_si128(a, b, 0x10); + T3 = _mm_clmulepi64_si128(a, b, 0x11); + + T1 = _mm_xor_si128(T1, T2); + T2 = _mm_slli_si128(T1, 8); + T1 = _mm_srli_si128(T1, 8); + T0 = _mm_xor_si128(T0, T2); + T3 = _mm_xor_si128(T3, T1); + + T4 = _mm_srli_epi32(T0, 31); + T0 = _mm_slli_epi32(T0, 1); + + T5 = _mm_srli_epi32(T3, 31); + T3 = _mm_slli_epi32(T3, 1); + + T2 = _mm_srli_si128(T4, 12); + T5 = _mm_slli_si128(T5, 4); + T4 = _mm_slli_si128(T4, 4); + T0 = _mm_or_si128(T0, T4); + T3 = _mm_or_si128(T3, T5); + T3 = _mm_or_si128(T3, T2); + + T4 = _mm_slli_epi32(T0, 31); + T5 = _mm_slli_epi32(T0, 30); + T2 = _mm_slli_epi32(T0, 25); + + T4 = _mm_xor_si128(T4, T5); + T4 = _mm_xor_si128(T4, T2); + T5 = _mm_srli_si128(T4, 4); + T3 = _mm_xor_si128(T3, T5); + T4 = _mm_slli_si128(T4, 12); + T0 = _mm_xor_si128(T0, T4); + T3 = _mm_xor_si128(T3, T0); + + T4 = _mm_srli_epi32(T0, 1); + T1 = _mm_srli_epi32(T0, 2); + T2 = _mm_srli_epi32(T0, 7); + T3 = _mm_xor_si128(T3, T1); + T3 = _mm_xor_si128(T3, T2); + T3 = _mm_xor_si128(T3, T4); + + T3 = _mm_shuffle_epi8(T3, BSWAP_MASK); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(&x[0]), T3); + } + +} diff --git a/src/lib/modes/aead/gcm/clmul/clmul.h b/src/lib/modes/aead/gcm/clmul/clmul.h new file mode 100644 index 000000000..ba197f2f7 --- /dev/null +++ b/src/lib/modes/aead/gcm/clmul/clmul.h @@ -0,0 +1,14 @@ +/* +* CLMUL hook +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +void gcm_multiply_clmul(byte x[16], const byte H[16]); + +} diff --git a/src/lib/modes/aead/gcm/clmul/info.txt b/src/lib/modes/aead/gcm/clmul/info.txt new file mode 100644 index 000000000..8a21b6ac2 --- /dev/null +++ b/src/lib/modes/aead/gcm/clmul/info.txt @@ -0,0 +1,8 @@ + +define GCM_CLMUL 20131227 + +need_isa clmul,ssse3 + + +clmul.h + diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp new file mode 100644 index 000000000..b39e6ac92 --- /dev/null +++ b/src/lib/modes/aead/gcm/gcm.cpp @@ -0,0 +1,290 @@ +/* +* GCM Mode Encryption +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_GCM_CLMUL) + #include + #include +#endif + +namespace Botan { + +void GHASH::gcm_multiply(secure_vector& x) const + { +#if defined(BOTAN_HAS_GCM_CLMUL) + if(CPUID::has_clmul()) + return gcm_multiply_clmul(&x[0], &m_H[0]); +#endif + + static const u64bit R = 0xE100000000000000; + + u64bit H[2] = { + load_be(&m_H[0], 0), + load_be(&m_H[0], 1) + }; + + u64bit Z[2] = { 0, 0 }; + + // SSE2 might be useful here + + for(size_t i = 0; i != 2; ++i) + { + const u64bit X = load_be(&x[0], i); + + for(size_t j = 0; j != 64; ++j) + { + if((X >> (63-j)) & 1) + { + Z[0] ^= H[0]; + Z[1] ^= H[1]; + } + + const u64bit r = (H[1] & 1) ? R : 0; + + H[1] = (H[0] << 63) | (H[1] >> 1); + H[0] = (H[0] >> 1) ^ r; + } + } + + store_be(&x[0], Z[0], Z[1]); + } + +void GHASH::ghash_update(secure_vector& ghash, + const byte input[], size_t length) + { + const size_t BS = 16; + + /* + This assumes if less than block size input then we're just on the + final block and should pad with zeros + */ + while(length) + { + const size_t to_proc = std::min(length, BS); + + xor_buf(&ghash[0], &input[0], to_proc); + + gcm_multiply(ghash); + + input += to_proc; + length -= to_proc; + } + } + +void GHASH::key_schedule(const byte key[], size_t length) + { + m_H.assign(key, key+length); + m_H_ad.resize(16); + m_ad_len = 0; + m_text_len = 0; + } + +void GHASH::start(const byte nonce[], size_t len) + { + m_nonce.assign(nonce, nonce + len); + m_ghash = m_H_ad; + } + +void GHASH::set_associated_data(const byte input[], size_t length) + { + zeroise(m_H_ad); + + ghash_update(m_H_ad, input, length); + m_ad_len = length; + } + +void GHASH::update(const byte input[], size_t length) + { + BOTAN_ASSERT(m_ghash.size() == 16, "Key was set"); + + m_text_len += length; + + ghash_update(m_ghash, input, length); + } + +void GHASH::add_final_block(secure_vector& hash, + size_t ad_len, size_t text_len) + { + secure_vector final_block(16); + store_be(&final_block[0], 8*ad_len, 8*text_len); + ghash_update(hash, &final_block[0], final_block.size()); + } + +secure_vector GHASH::final() + { + add_final_block(m_ghash, m_ad_len, m_text_len); + + secure_vector mac; + mac.swap(m_ghash); + + mac ^= m_nonce; + m_text_len = 0; + return mac; + } + +secure_vector GHASH::nonce_hash(const byte nonce[], size_t nonce_len) + { + BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time"); + secure_vector y0(16); + + ghash_update(y0, nonce, nonce_len); + add_final_block(y0, 0, nonce_len); + + return y0; + } + +void GHASH::clear() + { + zeroise(m_H); + zeroise(m_H_ad); + m_ghash.clear(); + m_text_len = m_ad_len = 0; + } + +/* +* GCM_Mode Constructor +*/ +GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) : + m_tag_size(tag_size), + m_cipher_name(cipher->name()) + { + if(cipher->block_size() != BS) + throw std::invalid_argument("GCM requires a 128 bit cipher so cannot be used with " + + cipher->name()); + + m_ghash.reset(new GHASH); + + m_ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher + + if(m_tag_size != 8 && m_tag_size != 16) + throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size)); + } + +void GCM_Mode::clear() + { + m_ctr->clear(); + m_ghash->clear(); + } + +std::string GCM_Mode::name() const + { + return (m_cipher_name + "/GCM"); + } + +size_t GCM_Mode::update_granularity() const + { + return 4096; // CTR-BE's internal block size + } + +Key_Length_Specification GCM_Mode::key_spec() const + { + return m_ctr->key_spec(); + } + +void GCM_Mode::key_schedule(const byte key[], size_t keylen) + { + m_ctr->set_key(key, keylen); + + const std::vector zeros(BS); + m_ctr->set_iv(&zeros[0], zeros.size()); + + secure_vector H(BS); + m_ctr->encipher(H); + m_ghash->set_key(H); + } + +void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len) + { + m_ghash->set_associated_data(ad, ad_len); + } + +secure_vector GCM_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + secure_vector y0(BS); + + if(nonce_len == 12) + { + copy_mem(&y0[0], nonce, nonce_len); + y0[15] = 1; + } + else + { + y0 = m_ghash->nonce_hash(nonce, nonce_len); + } + + m_ctr->set_iv(&y0[0], y0.size()); + + secure_vector m_enc_y0(BS); + m_ctr->encipher(m_enc_y0); + + m_ghash->start(&m_enc_y0[0], m_enc_y0.size()); + + return secure_vector(); + } + +void GCM_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + m_ctr->cipher(buf, buf, sz); + m_ghash->update(buf, sz); + } + +void GCM_Encryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + auto mac = m_ghash->final(); + buffer += std::make_pair(&mac[0], tag_size()); + } + +void GCM_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + m_ghash->update(buf, sz); + m_ctr->cipher(buf, buf, sz); + } + +void GCM_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); + + const size_t remaining = sz - tag_size(); + + // handle any final input before the tag + if(remaining) + { + m_ghash->update(buf, remaining); + m_ctr->cipher(buf, buf, remaining); + } + + auto mac = m_ghash->final(); + + const byte* included_tag = &buffer[remaining]; + + if(!same_mem(&mac[0], included_tag, tag_size())) + throw Integrity_Failure("GCM tag check failed"); + + buffer.resize(offset + remaining); + } + +} diff --git a/src/lib/modes/aead/gcm/gcm.h b/src/lib/modes/aead/gcm/gcm.h new file mode 100644 index 000000000..12d66a3d1 --- /dev/null +++ b/src/lib/modes/aead/gcm/gcm.h @@ -0,0 +1,150 @@ +/* +* GCM Mode +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_GCM_H__ +#define BOTAN_AEAD_GCM_H__ + +#include +#include +#include +#include + +namespace Botan { + +class GHASH; + +/** +* GCM Mode +*/ +class BOTAN_DLL GCM_Mode : public AEAD_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + void set_associated_data(const byte ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + // GCM supports arbitrary nonce lengths + bool valid_nonce_length(size_t) const override { return true; } + + size_t tag_size() const { return m_tag_size; } + + void clear(); + protected: + void key_schedule(const byte key[], size_t length) override; + + GCM_Mode(BlockCipher* cipher, size_t tag_size); + + const size_t BS = 16; + + const size_t m_tag_size; + const std::string m_cipher_name; + + std::unique_ptr m_ctr; + std::unique_ptr m_ghash; + }; + +/** +* GCM Encryption +*/ +class BOTAN_DLL GCM_Encryption : public GCM_Mode + { + public: + /** + * @param cipher the 128 bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + GCM_Encryption(BlockCipher* cipher, size_t tag_size = 16) : + GCM_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* GCM Decryption +*/ +class BOTAN_DLL GCM_Decryption : public GCM_Mode + { + public: + /** + * @param cipher the 128 bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + GCM_Decryption(BlockCipher* cipher, size_t tag_size = 16) : + GCM_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* GCM's GHASH +* Maybe a Transform? +*/ +class BOTAN_DLL GHASH : public SymmetricAlgorithm + { + public: + void set_associated_data(const byte ad[], size_t ad_len); + + secure_vector nonce_hash(const byte nonce[], size_t len); + + void start(const byte nonce[], size_t len); + + /* + * Assumes input len is multiple of 16 + */ + void update(const byte in[], size_t len); + + secure_vector final(); + + Key_Length_Specification key_spec() const { return Key_Length_Specification(16); } + + void clear(); + + std::string name() const { return "GHASH"; } + private: + void key_schedule(const byte key[], size_t key_len) override; + + void gcm_multiply(secure_vector& x) const; + + void ghash_update(secure_vector& x, + const byte input[], size_t input_len); + + void add_final_block(secure_vector& x, + size_t ad_len, size_t pt_len); + + secure_vector m_H; + secure_vector m_H_ad; + secure_vector m_nonce; + secure_vector m_ghash; + size_t m_ad_len = 0, m_text_len = 0; + }; + +} + +#endif diff --git a/src/lib/modes/aead/gcm/info.txt b/src/lib/modes/aead/gcm/info.txt new file mode 100644 index 000000000..cf5f68bb5 --- /dev/null +++ b/src/lib/modes/aead/gcm/info.txt @@ -0,0 +1,6 @@ +define AEAD_GCM 20131128 + + +block +ctr + diff --git a/src/lib/modes/aead/info.txt b/src/lib/modes/aead/info.txt new file mode 100644 index 000000000..102f05b7b --- /dev/null +++ b/src/lib/modes/aead/info.txt @@ -0,0 +1 @@ +define AEAD_MODES 20131128 diff --git a/src/lib/modes/aead/ocb/info.txt b/src/lib/modes/aead/ocb/info.txt new file mode 100644 index 000000000..be4cefdd0 --- /dev/null +++ b/src/lib/modes/aead/ocb/info.txt @@ -0,0 +1,6 @@ +define AEAD_OCB 20131128 + + +block +cmac + diff --git a/src/lib/modes/aead/ocb/ocb.cpp b/src/lib/modes/aead/ocb/ocb.cpp new file mode 100644 index 000000000..fd66bb2e9 --- /dev/null +++ b/src/lib/modes/aead/ocb/ocb.cpp @@ -0,0 +1,432 @@ +/* +* OCB Mode +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const size_t BS = 16; // intrinsic to OCB definition + +} + +// Has to be in Botan namespace so unique_ptr can reference it +class L_computer + { + public: + L_computer(const BlockCipher& cipher) + { + m_L_star.resize(cipher.block_size()); + cipher.encrypt(m_L_star); + m_L_dollar = poly_double(star()); + m_L.push_back(poly_double(dollar())); + } + + const secure_vector& star() const { return m_L_star; } + + const secure_vector& dollar() const { return m_L_dollar; } + + const secure_vector& operator()(size_t i) const { return get(i); } + + const secure_vector& compute_offsets(secure_vector& offset, + size_t block_index, + size_t blocks) const + { + m_offset_buf.resize(blocks*BS); + + for(size_t i = 0; i != blocks; ++i) + { // could be done in parallel + offset ^= get(ctz(block_index + 1 + i)); + copy_mem(&m_offset_buf[BS*i], &offset[0], BS); + } + + return m_offset_buf; + } + + private: + const secure_vector& get(size_t i) const + { + while(m_L.size() <= i) + m_L.push_back(poly_double(m_L.back())); + + return m_L.at(i); + } + + secure_vector poly_double(const secure_vector& in) const + { + return CMAC::poly_double(in, 0x87); + } + + secure_vector m_L_dollar, m_L_star; + mutable std::vector> m_L; + mutable secure_vector m_offset_buf; + }; + +namespace { + +/* +* OCB's HASH +*/ +secure_vector ocb_hash(const L_computer& L, + const BlockCipher& cipher, + const byte ad[], size_t ad_len) + { + secure_vector sum(BS); + secure_vector offset(BS); + + secure_vector buf(BS); + + const size_t ad_blocks = (ad_len / BS); + const size_t ad_remainder = (ad_len % BS); + + for(size_t i = 0; i != ad_blocks; ++i) + { + // this loop could run in parallel + offset ^= L(ctz(i+1)); + + buf = offset; + xor_buf(&buf[0], &ad[BS*i], BS); + + cipher.encrypt(buf); + + sum ^= buf; + } + + if(ad_remainder) + { + offset ^= L.star(); + + buf = offset; + xor_buf(&buf[0], &ad[BS*ad_blocks], ad_remainder); + buf[ad_len % BS] ^= 0x80; + + cipher.encrypt(buf); + + sum ^= buf; + } + + return sum; + } + +} + +OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) : + m_cipher(cipher), + m_checksum(m_cipher->parallel_bytes()), + m_offset(BS), + m_ad_hash(BS), + m_tag_size(tag_size) + { + if(m_cipher->block_size() != BS) + throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " + + m_cipher->name()); + + if(m_tag_size != 8 && m_tag_size != 12 && m_tag_size != 16) + throw std::invalid_argument("OCB cannot produce a " + std::to_string(m_tag_size) + + " byte tag"); + + } + +OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ } + +void OCB_Mode::clear() + { + m_cipher.reset(); + m_L.reset(); + + zeroise(m_ad_hash); + zeroise(m_offset); + zeroise(m_checksum); + } + +bool OCB_Mode::valid_nonce_length(size_t length) const + { + return (length > 0 && length < 16); + } + +std::string OCB_Mode::name() const + { + return m_cipher->name() + "/OCB"; // include tag size + } + +size_t OCB_Mode::update_granularity() const + { + return m_cipher->parallel_bytes(); + } + +Key_Length_Specification OCB_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +void OCB_Mode::key_schedule(const byte key[], size_t length) + { + m_cipher->set_key(key, length); + m_L.reset(new L_computer(*m_cipher)); + } + +void OCB_Mode::set_associated_data(const byte ad[], size_t ad_len) + { + BOTAN_ASSERT(m_L, "A key was set"); + m_ad_hash = ocb_hash(*m_L, *m_cipher, &ad[0], ad_len); + } + +secure_vector +OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len) + { + BOTAN_ASSERT(nonce_len < BS, "Nonce is less than 128 bits"); + + secure_vector nonce_buf(BS); + + copy_mem(&nonce_buf[BS - nonce_len], nonce, nonce_len); + nonce_buf[0] = ((tag_size() * 8) % 128) << 1; + nonce_buf[BS - nonce_len - 1] = 1; + + const byte bottom = nonce_buf[15] & 0x3F; + nonce_buf[15] &= 0xC0; + + const bool need_new_stretch = (m_last_nonce != nonce_buf); + + if(need_new_stretch) + { + m_last_nonce = nonce_buf; + + m_cipher->encrypt(nonce_buf); + + for(size_t i = 0; i != 8; ++i) + nonce_buf.push_back(nonce_buf[i] ^ nonce_buf[i+1]); + + m_stretch = nonce_buf; + } + + // now set the offset from stretch and bottom + + const size_t shift_bytes = bottom / 8; + const size_t shift_bits = bottom % 8; + + secure_vector offset(BS); + for(size_t i = 0; i != BS; ++i) + { + offset[i] = (m_stretch[i+shift_bytes] << shift_bits); + offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits)); + } + + return offset; + } + +secure_vector OCB_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + BOTAN_ASSERT(m_L, "A key was set"); + + m_offset = update_nonce(nonce, nonce_len); + zeroise(m_checksum); + m_block_index = 0; + + return secure_vector(); + } + +void OCB_Encryption::encrypt(byte buffer[], size_t blocks) + { + const L_computer& L = *m_L; // convenient name + + const size_t par_blocks = m_checksum.size() / BS; + + while(blocks) + { + const size_t proc_blocks = std::min(blocks, par_blocks); + const size_t proc_bytes = proc_blocks * BS; + + const auto& offsets = L.compute_offsets(m_offset, m_block_index, proc_blocks); + + xor_buf(&m_checksum[0], &buffer[0], proc_bytes); + + xor_buf(&buffer[0], &offsets[0], proc_bytes); + m_cipher->encrypt_n(&buffer[0], &buffer[0], proc_blocks); + xor_buf(&buffer[0], &offsets[0], proc_bytes); + + buffer += proc_bytes; + blocks -= proc_blocks; + m_block_index += proc_blocks; + } + } + +void OCB_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz % BS == 0, "Input length is an even number of blocks"); + + encrypt(buf, sz / BS); + } + +void OCB_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + if(sz) + { + const size_t final_full_blocks = sz / BS; + const size_t remainder_bytes = sz - (final_full_blocks * BS); + + encrypt(buf, final_full_blocks); + + if(remainder_bytes) + { + BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left"); + byte* remainder = &buf[sz - remainder_bytes]; + + xor_buf(&m_checksum[0], &remainder[0], remainder_bytes); + m_checksum[remainder_bytes] ^= 0x80; + + m_offset ^= m_L->star(); // Offset_* + + secure_vector buf(BS); + m_cipher->encrypt(m_offset, buf); + xor_buf(&remainder[0], &buf[0], remainder_bytes); + } + } + + secure_vector checksum(BS); + + // fold checksum + for(size_t i = 0; i != m_checksum.size(); ++i) + checksum[i % checksum.size()] ^= m_checksum[i]; + + // now compute the tag + secure_vector mac = m_offset; + mac ^= checksum; + mac ^= m_L->dollar(); + + m_cipher->encrypt(mac); + + mac ^= m_ad_hash; + + buffer += std::make_pair(&mac[0], tag_size()); + + zeroise(m_checksum); + zeroise(m_offset); + m_block_index = 0; + } + +void OCB_Decryption::decrypt(byte buffer[], size_t blocks) + { + const L_computer& L = *m_L; // convenient name + + const size_t par_bytes = m_cipher->parallel_bytes(); + + BOTAN_ASSERT(par_bytes % BS == 0, "Cipher is parallel in full blocks"); + + const size_t par_blocks = par_bytes / BS; + + while(blocks) + { + const size_t proc_blocks = std::min(blocks, par_blocks); + const size_t proc_bytes = proc_blocks * BS; + + const auto& offsets = L.compute_offsets(m_offset, m_block_index, proc_blocks); + + xor_buf(&buffer[0], &offsets[0], proc_bytes); + m_cipher->decrypt_n(&buffer[0], &buffer[0], proc_blocks); + xor_buf(&buffer[0], &offsets[0], proc_bytes); + + xor_buf(&m_checksum[0], &buffer[0], proc_bytes); + + buffer += proc_bytes; + blocks -= proc_blocks; + m_block_index += proc_blocks; + } + } + +void OCB_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz % BS == 0, "Input length is an even number of blocks"); + + decrypt(buf, sz / BS); + } + +void OCB_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); + + const size_t remaining = sz - tag_size(); + + if(remaining) + { + const size_t final_full_blocks = remaining / BS; + const size_t final_bytes = remaining - (final_full_blocks * BS); + + decrypt(&buf[0], final_full_blocks); + + if(final_bytes) + { + BOTAN_ASSERT(final_bytes < BS, "Only a partial block left"); + + byte* remainder = &buf[remaining - final_bytes]; + + m_offset ^= m_L->star(); // Offset_* + + secure_vector pad(BS); + m_cipher->encrypt(m_offset, pad); // P_* + + xor_buf(&remainder[0], &pad[0], final_bytes); + + xor_buf(&m_checksum[0], &remainder[0], final_bytes); + m_checksum[final_bytes] ^= 0x80; + } + } + + secure_vector checksum(BS); + + // fold checksum + for(size_t i = 0; i != m_checksum.size(); ++i) + checksum[i % checksum.size()] ^= m_checksum[i]; + + // compute the mac + secure_vector mac = m_offset; + mac ^= checksum; + mac ^= m_L->dollar(); + + m_cipher->encrypt(mac); + + mac ^= m_ad_hash; + + // reset state + zeroise(m_checksum); + zeroise(m_offset); + m_block_index = 0; + + // compare mac + const byte* included_tag = &buf[remaining]; + + if(!same_mem(&mac[0], included_tag, tag_size())) + throw Integrity_Failure("OCB tag check failed"); + + // remove tag from end of message + buffer.resize(remaining + offset); + } + +} diff --git a/src/lib/modes/aead/ocb/ocb.h b/src/lib/modes/aead/ocb/ocb.h new file mode 100644 index 000000000..e7d042de3 --- /dev/null +++ b/src/lib/modes/aead/ocb/ocb.h @@ -0,0 +1,124 @@ +/* +* OCB Mode +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_OCB_H__ +#define BOTAN_AEAD_OCB_H__ + +#include +#include +#include +#include + +namespace Botan { + +class L_computer; + +/** +* OCB Mode (base class for OCB_Encryption and OCB_Decryption). Note +* that OCB is patented, but is freely licensed in some circumstances. +* +* @see "The OCB Authenticated-Encryption Algorithm" internet draft + http://tools.ietf.org/html/draft-irtf-cfrg-ocb-03 +* @see Free Licenses http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm +* @see OCB home page http://www.cs.ucdavis.edu/~rogaway/ocb +*/ +class BOTAN_DLL OCB_Mode : public AEAD_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + void set_associated_data(const byte ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t) const override; + + size_t tag_size() const { return m_tag_size; } + + void clear(); + + ~OCB_Mode(); + protected: + /** + * @param cipher the 128-bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + OCB_Mode(BlockCipher* cipher, size_t tag_size); + + void key_schedule(const byte key[], size_t length) override; + + // fixme make these private + std::unique_ptr m_cipher; + std::unique_ptr m_L; + + size_t m_block_index = 0; + + secure_vector m_checksum; + secure_vector m_offset; + secure_vector m_ad_hash; + private: + secure_vector update_nonce(const byte nonce[], size_t nonce_len); + + size_t m_tag_size = 0; + secure_vector m_last_nonce; + secure_vector m_stretch; + }; + +class BOTAN_DLL OCB_Encryption : public OCB_Mode + { + public: + /** + * @param cipher the 128-bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + OCB_Encryption(BlockCipher* cipher, size_t tag_size = 16) : + OCB_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + private: + void encrypt(byte input[], size_t blocks); + }; + +class BOTAN_DLL OCB_Decryption : public OCB_Mode + { + public: + /** + * @param cipher the 128-bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + OCB_Decryption(BlockCipher* cipher, size_t tag_size = 16) : + OCB_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + private: + void decrypt(byte input[], size_t blocks); + }; + +} + +#endif diff --git a/src/lib/modes/aead/siv/info.txt b/src/lib/modes/aead/siv/info.txt new file mode 100644 index 000000000..b1e38568e --- /dev/null +++ b/src/lib/modes/aead/siv/info.txt @@ -0,0 +1,3 @@ +define AEAD_SIV 20131202 + +load_on auto diff --git a/src/lib/modes/aead/siv/siv.cpp b/src/lib/modes/aead/siv/siv.cpp new file mode 100644 index 000000000..a89c3dd08 --- /dev/null +++ b/src/lib/modes/aead/siv/siv.cpp @@ -0,0 +1,180 @@ +/* +* SIV Mode Encryption +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +SIV_Mode::SIV_Mode(BlockCipher* cipher) : + m_name(cipher->name() + "/SIV"), + m_ctr(new CTR_BE(cipher->clone())), + m_cmac(new CMAC(cipher)) + { + } + +void SIV_Mode::clear() + { + m_ctr.reset(); + m_nonce.clear(); + m_msg_buf.clear(); + m_ad_macs.clear(); + } + +std::string SIV_Mode::name() const + { + return m_name; + } + +bool SIV_Mode::valid_nonce_length(size_t) const + { + return true; + } + +size_t SIV_Mode::update_granularity() const + { + /* + This value does not particularly matter as regardless SIV_Mode::update + buffers all input, so in theory this could be 1. However as for instance + Transformation_Filter creates update_granularity() byte buffers, use a + somewhat large size to avoid bouncing on a tiny buffer. + */ + return 128; + } + +Key_Length_Specification SIV_Mode::key_spec() const + { + return m_cmac->key_spec().multiple(2); + } + +void SIV_Mode::key_schedule(const byte key[], size_t length) + { + const size_t keylen = length / 2; + m_cmac->set_key(key, keylen); + m_ctr->set_key(key + keylen, keylen); + m_ad_macs.clear(); + } + +void SIV_Mode::set_associated_data_n(size_t n, const byte ad[], size_t length) + { + if(n >= m_ad_macs.size()) + m_ad_macs.resize(n+1); + + m_ad_macs[n] = m_cmac->process(ad, length); + } + +secure_vector SIV_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + if(nonce_len) + m_nonce = m_cmac->process(nonce, nonce_len); + else + m_nonce.clear(); + + m_msg_buf.clear(); + + return secure_vector(); + } + +void SIV_Mode::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz); + buffer.resize(offset); // truncate msg + } + +secure_vector SIV_Mode::S2V(const byte* text, size_t text_len) + { + const byte zero[16] = { 0 }; + + secure_vector V = cmac().process(zero, 16); + + for(size_t i = 0; i != m_ad_macs.size(); ++i) + { + V = CMAC::poly_double(V, 0x87); + V ^= m_ad_macs[i]; + } + + if(m_nonce.size()) + { + V = CMAC::poly_double(V, 0x87); + V ^= m_nonce; + } + + if(text_len < 16) + { + V = CMAC::poly_double(V, 0x87); + xor_buf(&V[0], text, text_len); + V[text_len] ^= 0x80; + return cmac().process(V); + } + + cmac().update(text, text_len - 16); + xor_buf(&V[0], &text[text_len - 16], 16); + cmac().update(V); + + return cmac().final(); + } + +void SIV_Mode::set_ctr_iv(secure_vector V) + { + V[8] &= 0x7F; + V[12] &= 0x7F; + + ctr().set_iv(&V[0], V.size()); + } + +void SIV_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + + secure_vector V = S2V(&buffer[offset], buffer.size() - offset); + + buffer.insert(buffer.begin() + offset, V.begin(), V.end()); + + set_ctr_iv(V); + ctr().cipher1(&buffer[offset + V.size()], buffer.size() - offset - V.size()); + } + +void SIV_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + + const size_t sz = buffer.size() - offset; + + BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); + + secure_vector V(&buffer[offset], &buffer[offset + 16]); + + set_ctr_iv(V); + + ctr().cipher(&buffer[offset + V.size()], + &buffer[offset], + buffer.size() - offset - V.size()); + + secure_vector T = S2V(&buffer[offset], buffer.size() - offset - V.size()); + + if(T != V) + throw Integrity_Failure("SIV tag check failed"); + + buffer.resize(buffer.size() - tag_size()); + } + +} diff --git a/src/lib/modes/aead/siv/siv.h b/src/lib/modes/aead/siv/siv.h new file mode 100644 index 000000000..31df4d049 --- /dev/null +++ b/src/lib/modes/aead/siv/siv.h @@ -0,0 +1,114 @@ +/* +* SIV Mode +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_SIV_H__ +#define BOTAN_AEAD_SIV_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Base class for SIV encryption and decryption (@see RFC 5297) +*/ +class BOTAN_DLL SIV_Mode : public AEAD_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + void update(secure_vector& blocks, size_t offset = 0) override; + + void set_associated_data_n(size_t n, const byte ad[], size_t ad_len); + + void set_associated_data(const byte ad[], size_t ad_len) override + { + set_associated_data_n(0, ad, ad_len); + } + + std::string name() const override; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t) const override; + + void clear(); + + size_t tag_size() const { return 16; } + + protected: + SIV_Mode(BlockCipher* cipher); + + StreamCipher& ctr() { return *m_ctr; } + + void set_ctr_iv(secure_vector V); + + secure_vector& msg_buf() { return m_msg_buf; } + + secure_vector S2V(const byte text[], size_t text_len); + private: + MessageAuthenticationCode& cmac() { return *m_cmac; } + + void key_schedule(const byte key[], size_t length) override; + + const std::string m_name; + + std::unique_ptr m_ctr; + std::unique_ptr m_cmac; + secure_vector m_nonce, m_msg_buf; + std::vector> m_ad_macs; + }; + +/** +* SIV Encryption +*/ +class BOTAN_DLL SIV_Encryption : public SIV_Mode + { + public: + /** + * @param cipher a block cipher + */ + SIV_Encryption(BlockCipher* cipher) : SIV_Mode(cipher) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + }; + +/** +* SIV Decryption +*/ +class BOTAN_DLL SIV_Decryption : public SIV_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + */ + SIV_Decryption(BlockCipher* cipher) : SIV_Mode(cipher) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + }; + +} + +#endif diff --git a/src/lib/modes/cbc/cbc.cpp b/src/lib/modes/cbc/cbc.cpp new file mode 100644 index 000000000..31834bade --- /dev/null +++ b/src/lib/modes/cbc/cbc.cpp @@ -0,0 +1,299 @@ +/* +* CBC Mode +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + m_cipher(cipher), + m_padding(padding), + m_state(m_cipher->block_size()) + { + if(m_padding && !m_padding->valid_blocksize(cipher->block_size())) + throw std::invalid_argument("Padding " + m_padding->name() + + " cannot be used with " + + cipher->name() + "/CBC"); + } + +void CBC_Mode::clear() + { + m_cipher->clear(); + m_state.clear(); + } + +std::string CBC_Mode::name() const + { + if(m_padding) + return cipher().name() + "/CBC/" + padding().name(); + else + return cipher().name() + "/CBC/CTS"; + } + +size_t CBC_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +Key_Length_Specification CBC_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CBC_Mode::default_nonce_length() const + { + return cipher().block_size(); + } + +bool CBC_Mode::valid_nonce_length(size_t n) const + { + return (n == 0 || n == cipher().block_size()); + } + +void CBC_Mode::key_schedule(const byte key[], size_t length) + { + m_cipher->set_key(key, length); + } + +secure_vector CBC_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + /* + * A nonce of zero length means carry the last ciphertext value over + * as the new IV, as unfortunately some protocols require this. If + * this is the first message then we use an IV of all zeros. + */ + if(nonce_len) + m_state.assign(nonce, nonce + nonce_len); + + return secure_vector(); + } + +size_t CBC_Encryption::minimum_final_size() const + { + return 0; + } + +size_t CBC_Encryption::output_length(size_t input_length) const + { + return round_up(input_length, cipher().block_size()); + } + +void CBC_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks"); + const size_t blocks = sz / BS; + + if(blocks) + { + xor_buf(&buf[0], state_ptr(), BS); + cipher().encrypt(&buf[0]); + + for(size_t i = 1; i != blocks; ++i) + { + xor_buf(&buf[BS*i], &buf[BS*(i-1)], BS); + cipher().encrypt(&buf[BS*i]); + } + + state().assign(&buf[BS*(blocks-1)], &buf[BS*blocks]); + } + } + +void CBC_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + const size_t BS = cipher().block_size(); + + const size_t bytes_in_final_block = (buffer.size()-offset) % BS; + + padding().add_padding(buffer, bytes_in_final_block, BS); + + if((buffer.size()-offset) % BS) + throw std::runtime_error("Did not pad to full block size in " + name()); + + update(buffer, offset); + } + +bool CTS_Encryption::valid_nonce_length(size_t n) const + { + return (n == cipher().block_size()); + } + +size_t CTS_Encryption::minimum_final_size() const + { + return cipher().block_size() + 1; + } + +size_t CTS_Encryption::output_length(size_t input_length) const + { + return input_length; // no ciphertext expansion in CTS + } + +void CTS_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + byte* buf = &buffer[offset]; + const size_t sz = buffer.size() - offset; + + const size_t BS = cipher().block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to encrypt"); + + if(sz % BS == 0) + { + update(buffer, offset); + + // swap last two blocks + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + } + else + { + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(&last[0], state_ptr(), BS); + cipher().encrypt(&last[0]); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + std::swap(last[i], last[i + BS]); + last[i] ^= last[i + BS]; + } + + cipher().encrypt(&last[0]); + + buffer += last; + } + } + +size_t CBC_Decryption::output_length(size_t input_length) const + { + return input_length; // precise for CTS, worst case otherwise + } + +size_t CBC_Decryption::minimum_final_size() const + { + return cipher().block_size(); + } + +void CBC_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + while(blocks) + { + const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); + + cipher().decrypt_n(buf, &m_tempbuf[0], to_proc / BS); + + xor_buf(&m_tempbuf[0], state_ptr(), BS); + xor_buf(&m_tempbuf[BS], buf, to_proc - BS); + copy_mem(state_ptr(), buf + (to_proc - BS), BS); + + copy_mem(buf, &m_tempbuf[0], to_proc); + + buf += to_proc; + blocks -= to_proc / BS; + } + } + +void CBC_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + + const size_t BS = cipher().block_size(); + + if(sz == 0 || sz % BS) + throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); + + update(buffer, offset); + + const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); + buffer.resize(buffer.size() - pad_bytes); // remove padding + } + +bool CTS_Decryption::valid_nonce_length(size_t n) const + { + return (n == cipher().block_size()); + } + +size_t CTS_Decryption::minimum_final_size() const + { + return cipher().block_size() + 1; + } + +void CTS_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to decrypt"); + + if(sz % BS == 0) + { + // swap last two blocks + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + + update(buffer, offset); + } + else + { + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + cipher().decrypt(&last[0]); + xor_buf(&last[0], &last[BS], final_bytes - BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + cipher().decrypt(&last[0]); + xor_buf(&last[0], state_ptr(), BS); + + buffer += last; + } + + } + +} diff --git a/src/lib/modes/cbc/cbc.h b/src/lib/modes/cbc/cbc.h new file mode 100644 index 000000000..0a10f3661 --- /dev/null +++ b/src/lib/modes/cbc/cbc.h @@ -0,0 +1,132 @@ +/* +* CBC mode +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODE_CBC_H__ +#define BOTAN_MODE_CBC_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* CBC Mode +*/ +class BOTAN_DLL CBC_Mode : public Cipher_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear(); + protected: + CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding); + + const BlockCipher& cipher() const { return *m_cipher; } + + const BlockCipherModePaddingMethod& padding() const + { + BOTAN_ASSERT_NONNULL(m_padding); + return *m_padding; + } + + secure_vector& state() { return m_state; } + + byte* state_ptr() { return &m_state[0]; } + + private: + void key_schedule(const byte key[], size_t length) override; + + std::unique_ptr m_cipher; + std::unique_ptr m_padding; + secure_vector m_state; + }; + +/** +* CBC Encryption +*/ +class BOTAN_DLL CBC_Encryption : public CBC_Mode + { + public: + CBC_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + }; + +/** +* CBC Encryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_DLL CTS_Encryption : public CBC_Encryption + { + public: + CTS_Encryption(BlockCipher* cipher) : CBC_Encryption(cipher, nullptr) {} + + size_t output_length(size_t input_length) const override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const; + }; + +/** +* CBC Decryption +*/ +class BOTAN_DLL CBC_Decryption : public CBC_Mode + { + public: + CBC_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding), m_tempbuf(update_granularity()) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + private: + secure_vector m_tempbuf; + }; + +/** +* CBC Decryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_DLL CTS_Decryption : public CBC_Decryption + { + public: + CTS_Decryption(BlockCipher* cipher) : CBC_Decryption(cipher, nullptr) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const; + }; + +} + +#endif diff --git a/src/lib/modes/cbc/info.txt b/src/lib/modes/cbc/info.txt new file mode 100644 index 000000000..ce59deba0 --- /dev/null +++ b/src/lib/modes/cbc/info.txt @@ -0,0 +1,5 @@ +define MODE_CBC 20131128 + + +mode_pad + diff --git a/src/lib/modes/cfb/cfb.cpp b/src/lib/modes/cfb/cfb.cpp new file mode 100644 index 000000000..7721e1487 --- /dev/null +++ b/src/lib/modes/cfb/cfb.cpp @@ -0,0 +1,150 @@ +/* +* CFB Mode +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +CFB_Mode::CFB_Mode(BlockCipher* cipher, size_t feedback_bits) : + m_cipher(cipher), + m_feedback_bytes(feedback_bits ? feedback_bits / 8 : cipher->block_size()) + { + if(feedback_bits % 8 || feedback() > cipher->block_size()) + throw std::invalid_argument(name() + ": feedback bits " + + std::to_string(feedback_bits) + " not supported"); + } + +void CFB_Mode::clear() + { + m_cipher->clear(); + m_shift_register.clear(); + } + +std::string CFB_Mode::name() const + { + if(feedback() == cipher().block_size()) + return cipher().name() + "/CFB"; + else + return cipher().name() + "/CFB(" + std::to_string(feedback()*8) + ")"; + } + +size_t CFB_Mode::output_length(size_t input_length) const + { + return input_length; + } + +size_t CFB_Mode::update_granularity() const + { + return feedback(); + } + +size_t CFB_Mode::minimum_final_size() const + { + return 0; + } + +Key_Length_Specification CFB_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CFB_Mode::default_nonce_length() const + { + return cipher().block_size(); + } + +bool CFB_Mode::valid_nonce_length(size_t n) const + { + return (n == cipher().block_size()); + } + +void CFB_Mode::key_schedule(const byte key[], size_t length) + { + m_cipher->set_key(key, length); + } + +secure_vector CFB_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_shift_register.assign(nonce, nonce + nonce_len); + m_keystream_buf.resize(m_shift_register.size()); + cipher().encrypt(m_shift_register, m_keystream_buf); + + return secure_vector(); + } + +void CFB_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + secure_vector& state = shift_register(); + const size_t shift = feedback(); + + while(sz) + { + const size_t took = std::min(shift, sz); + xor_buf(&buf[0], &keystream_buf()[0], took); + + // Assumes feedback-sized block except for last input + copy_mem(&state[0], &state[shift], BS - shift); + copy_mem(&state[BS-shift], &buf[0], shift); + cipher().encrypt(state, keystream_buf()); + + buf += took; + sz -= took; + } + } + +void CFB_Encryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + } + +void CFB_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + secure_vector& state = shift_register(); + const size_t shift = feedback(); + + while(sz) + { + const size_t took = std::min(shift, sz); + + // first update shift register with ciphertext + copy_mem(&state[0], &state[shift], BS - shift); + copy_mem(&state[BS-shift], &buf[0], took); + + // then decrypt + xor_buf(&buf[0], &keystream_buf()[0], took); + + // then update keystream + cipher().encrypt(state, keystream_buf()); + + buf += took; + sz -= took; + } + } + +void CFB_Decryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + } + +} diff --git a/src/lib/modes/cfb/cfb.h b/src/lib/modes/cfb/cfb.h new file mode 100644 index 000000000..48be0a2d9 --- /dev/null +++ b/src/lib/modes/cfb/cfb.h @@ -0,0 +1,91 @@ +/* +* CFB mode +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODE_CFB_H__ +#define BOTAN_MODE_CFB_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* CFB Mode +*/ +class BOTAN_DLL CFB_Mode : public Cipher_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + std::string name() const override; + + size_t update_granularity() const override; + + size_t minimum_final_size() const override; + + Key_Length_Specification key_spec() const override; + + size_t output_length(size_t input_length) const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear(); + protected: + CFB_Mode(BlockCipher* cipher, size_t feedback_bits); + + const BlockCipher& cipher() const { return *m_cipher; } + + size_t feedback() const { return m_feedback_bytes; } + + secure_vector& shift_register() { return m_shift_register; } + + secure_vector& keystream_buf() { return m_keystream_buf; } + + private: + void key_schedule(const byte key[], size_t length) override; + + std::unique_ptr m_cipher; + secure_vector m_shift_register; + secure_vector m_keystream_buf; + size_t m_feedback_bytes; + }; + +/** +* CFB Encryption +*/ +class BOTAN_DLL CFB_Encryption : public CFB_Mode + { + public: + CFB_Encryption(BlockCipher* cipher, size_t feedback_bits) : + CFB_Mode(cipher, feedback_bits) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* CFB Decryption +*/ +class BOTAN_DLL CFB_Decryption : public CFB_Mode + { + public: + CFB_Decryption(BlockCipher* cipher, size_t feedback_bits) : + CFB_Mode(cipher, feedback_bits) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/src/lib/modes/cfb/info.txt b/src/lib/modes/cfb/info.txt new file mode 100644 index 000000000..8d0e20a84 --- /dev/null +++ b/src/lib/modes/cfb/info.txt @@ -0,0 +1 @@ +define MODE_CFB 20131128 diff --git a/src/lib/modes/cipher_mode.h b/src/lib/modes/cipher_mode.h new file mode 100644 index 000000000..91e2af5a9 --- /dev/null +++ b/src/lib/modes/cipher_mode.h @@ -0,0 +1,30 @@ +/* +* Cipher Modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CIPHER_MODE_H__ +#define BOTAN_CIPHER_MODE_H__ + +#include + +namespace Botan { + +/** +* Interface for cipher modes +*/ +class BOTAN_DLL Cipher_Mode : public Transformation + { + public: + /** + * Returns true iff this mode provides authentication as well as + * confidentiality. + */ + virtual bool authenticated() const { return false; } + }; + +} + +#endif diff --git a/src/lib/modes/ecb/ecb.cpp b/src/lib/modes/ecb/ecb.cpp new file mode 100644 index 000000000..f026eb035 --- /dev/null +++ b/src/lib/modes/ecb/ecb.cpp @@ -0,0 +1,149 @@ +/* +* ECB Mode +* (C) 1999-2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +ECB_Mode::ECB_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + m_cipher(cipher), + m_padding(padding) + { + if(!m_padding->valid_blocksize(cipher->block_size())) + throw std::invalid_argument("Padding " + m_padding->name() + + " cannot be used with " + + cipher->name() + "/ECB"); + } + +void ECB_Mode::clear() + { + m_cipher->clear(); + } + +std::string ECB_Mode::name() const + { + return cipher().name() + "/ECB/" + padding().name(); + } + +size_t ECB_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +Key_Length_Specification ECB_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t ECB_Mode::default_nonce_length() const + { + return 0; + } + +bool ECB_Mode::valid_nonce_length(size_t n) const + { + return (n == 0); + } + +void ECB_Mode::key_schedule(const byte key[], size_t length) + { + m_cipher->set_key(key, length); + } + +secure_vector ECB_Mode::start(const byte[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + return secure_vector(); + } + +size_t ECB_Encryption::minimum_final_size() const + { + return 0; + } + +size_t ECB_Encryption::output_length(size_t input_length) const + { + return round_up(input_length, cipher().block_size()); + } + +void ECB_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "ECB input is full blocks"); + const size_t blocks = sz / BS; + + cipher().encrypt_n(&buf[0], &buf[0], blocks); + } + +void ECB_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + + const size_t BS = cipher().block_size(); + + const size_t bytes_in_final_block = sz % BS; + + padding().add_padding(buffer, bytes_in_final_block, BS); + + if(buffer.size() % BS) + throw std::runtime_error("Did not pad to full block size in " + name()); + + update(buffer, offset); + } + +size_t ECB_Decryption::output_length(size_t input_length) const + { + return input_length; + } + +size_t ECB_Decryption::minimum_final_size() const + { + return cipher().block_size(); + } + +void ECB_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + cipher().decrypt_n(&buf[0], &buf[0], blocks); + } + +void ECB_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + + const size_t BS = cipher().block_size(); + + if(sz == 0 || sz % BS) + throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); + + update(buffer, offset); + + const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); + buffer.resize(buffer.size() - pad_bytes); // remove padding + } + +} diff --git a/src/lib/modes/ecb/ecb.h b/src/lib/modes/ecb/ecb.h new file mode 100644 index 000000000..441eafbc1 --- /dev/null +++ b/src/lib/modes/ecb/ecb.h @@ -0,0 +1,89 @@ +/* +* ECB Mode +* (C) 1999-2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODE_ECB_H__ +#define BOTAN_MODE_ECB_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* ECB mode +*/ +class BOTAN_DLL ECB_Mode : public Cipher_Mode + { + public: + secure_vector start(const byte nonce[], size_t nonce_len) override; + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear(); + protected: + ECB_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding); + + const BlockCipher& cipher() const { return *m_cipher; } + + const BlockCipherModePaddingMethod& padding() const { return *m_padding; } + + private: + void key_schedule(const byte key[], size_t length) override; + + std::unique_ptr m_cipher; + std::unique_ptr m_padding; + }; + +/** +* ECB Encryption +*/ +class BOTAN_DLL ECB_Encryption : public ECB_Mode + { + public: + ECB_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + ECB_Mode(cipher, padding) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + }; + +/** +* ECB Decryption +*/ +class BOTAN_DLL ECB_Decryption : public ECB_Mode + { + public: + ECB_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + ECB_Mode(cipher, padding) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + }; + +} + +#endif diff --git a/src/lib/modes/ecb/info.txt b/src/lib/modes/ecb/info.txt new file mode 100644 index 000000000..5e7737717 --- /dev/null +++ b/src/lib/modes/ecb/info.txt @@ -0,0 +1,5 @@ +define MODE_ECB 20131128 + + +mode_pad + diff --git a/src/lib/modes/info.txt b/src/lib/modes/info.txt new file mode 100644 index 000000000..0dcb0cd59 --- /dev/null +++ b/src/lib/modes/info.txt @@ -0,0 +1,4 @@ + + +block + diff --git a/src/lib/modes/mode_pad/info.txt b/src/lib/modes/mode_pad/info.txt new file mode 100644 index 000000000..e9df6334b --- /dev/null +++ b/src/lib/modes/mode_pad/info.txt @@ -0,0 +1 @@ +define CIPHER_MODE_PADDING 20131128 diff --git a/src/lib/modes/mode_pad/mode_pad.cpp b/src/lib/modes/mode_pad/mode_pad.cpp new file mode 100644 index 000000000..918964c74 --- /dev/null +++ b/src/lib/modes/mode_pad/mode_pad.cpp @@ -0,0 +1,103 @@ +/* +* CBC Padding Methods +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Pad with PKCS #7 Method +*/ +void PKCS7_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t block_size) const + { + const byte pad_value = block_size - last_byte_pos; + + for(size_t i = 0; i != pad_value; ++i) + buffer.push_back(pad_value); + } + +/* +* Unpad with PKCS #7 Method +*/ +size_t PKCS7_Padding::unpad(const byte block[], size_t size) const + { + size_t position = block[size-1]; + + if(position > size) + throw Decoding_Error("Bad padding in " + name()); + + for(size_t j = size-position; j != size-1; ++j) + if(block[j] != position) + throw Decoding_Error("Bad padding in " + name()); + + return (size-position); + } + +/* +* Pad with ANSI X9.23 Method +*/ +void ANSI_X923_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t block_size) const + { + const byte pad_value = block_size - last_byte_pos; + + for(size_t i = last_byte_pos; i < block_size; ++i) + buffer.push_back(0); + buffer.push_back(pad_value); + } + +/* +* Unpad with ANSI X9.23 Method +*/ +size_t ANSI_X923_Padding::unpad(const byte block[], size_t size) const + { + size_t position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(size_t j = size-position; j != size-1; ++j) + if(block[j] != 0) + throw Decoding_Error(name()); + return (size-position); + } + +/* +* Pad with One and Zeros Method +*/ +void OneAndZeros_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t block_size) const + { + buffer.push_back(0x80); + + for(size_t i = last_byte_pos + 1; i % block_size; ++i) + buffer.push_back(0x00); + } + +/* +* Unpad with One and Zeros Method +*/ +size_t OneAndZeros_Padding::unpad(const byte block[], size_t size) const + { + while(size) + { + if(block[size-1] == 0x80) + break; + if(block[size-1] != 0x00) + throw Decoding_Error(name()); + size--; + } + if(!size) + throw Decoding_Error(name()); + return (size-1); + } + + +} diff --git a/src/lib/modes/mode_pad/mode_pad.h b/src/lib/modes/mode_pad/mode_pad.h new file mode 100644 index 000000000..e7c38a196 --- /dev/null +++ b/src/lib/modes/mode_pad/mode_pad.h @@ -0,0 +1,124 @@ +/* +* ECB/CBC Padding Methods +* (C) 1999-2008,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODE_PADDING_H__ +#define BOTAN_MODE_PADDING_H__ + +#include +#include + +namespace Botan { + +/** +* Block Cipher Mode Padding Method +* This class is pretty limited, it cannot deal well with +* randomized padding methods, or any padding method that +* wants to add more than one block. For instance, it should +* be possible to define cipher text stealing mode as simply +* a padding mode for CBC, which happens to consume the last +* two block (and requires use of the block cipher). +*/ +class BOTAN_DLL BlockCipherModePaddingMethod + { + public: + virtual void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const = 0; + + /** + * @param block the last block + * @param size the of the block + */ + virtual size_t unpad(const byte block[], + size_t size) const = 0; + + /** + * @param block_size of the cipher + * @return valid block size for this padding mode + */ + virtual bool valid_blocksize(size_t block_size) const = 0; + + /** + * @return name of the mode + */ + virtual std::string name() const = 0; + + /** + * virtual destructor + */ + virtual ~BlockCipherModePaddingMethod() {} + }; + +/** +* PKCS#7 Padding +*/ +class BOTAN_DLL PKCS7_Padding : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const byte[], size_t) const; + + bool valid_blocksize(size_t bs) const { return (bs > 0 && bs < 256); } + + std::string name() const { return "PKCS7"; } + }; + +/** +* ANSI X9.23 Padding +*/ +class BOTAN_DLL ANSI_X923_Padding : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const byte[], size_t) const; + + bool valid_blocksize(size_t bs) const { return (bs > 0 && bs < 256); } + + std::string name() const { return "X9.23"; } + }; + +/** +* One And Zeros Padding +*/ +class BOTAN_DLL OneAndZeros_Padding : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const byte[], size_t) const; + + bool valid_blocksize(size_t bs) const { return (bs > 0); } + + std::string name() const { return "OneAndZeros"; } + }; + +/** +* Null Padding +*/ +class BOTAN_DLL Null_Padding : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector&, size_t, size_t) const override {} + + size_t unpad(const byte[], size_t size) const { return size; } + + bool valid_blocksize(size_t) const { return true; } + + std::string name() const { return "NoPadding"; } + }; + +} + +#endif diff --git a/src/lib/modes/xts/info.txt b/src/lib/modes/xts/info.txt new file mode 100644 index 000000000..5f5dc7834 --- /dev/null +++ b/src/lib/modes/xts/info.txt @@ -0,0 +1 @@ +define MODE_XTS 20131128 diff --git a/src/lib/modes/xts/xts.cpp b/src/lib/modes/xts/xts.cpp new file mode 100644 index 000000000..02da5fa5d --- /dev/null +++ b/src/lib/modes/xts/xts.cpp @@ -0,0 +1,285 @@ +/* +* XTS Mode +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void poly_double_128(byte out[], const byte in[]) + { + u64bit X0 = load_le(in, 0); + u64bit X1 = load_le(in, 1); + + const bool carry = (X1 >> 63); + + X1 = (X1 << 1) | (X0 >> 63); + X0 = (X0 << 1); + + if(carry) + X0 ^= 0x87; + + store_le(out, X0, X1); + } + +void poly_double_64(byte out[], const byte in[]) + { + u64bit X = load_le(in, 0); + const bool carry = (X >> 63); + X <<= 1; + if(carry) + X ^= 0x1B; + store_le(X, out); + } + +inline void poly_double(byte out[], const byte in[], size_t size) + { + if(size == 8) + poly_double_64(out, in); + else + poly_double_128(out, in); + } + +} + +XTS_Mode::XTS_Mode(BlockCipher* cipher) : m_cipher(cipher) + { + if(m_cipher->block_size() != 8 && m_cipher->block_size() != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + m_tweak_cipher.reset(m_cipher->clone()); + m_tweak.resize(update_granularity()); + } + +void XTS_Mode::clear() + { + m_cipher->clear(); + m_tweak_cipher->clear(); + zeroise(m_tweak); + } + +std::string XTS_Mode::name() const + { + return cipher().name() + "/XTS"; + } + +size_t XTS_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +size_t XTS_Mode::minimum_final_size() const + { + return cipher().block_size() + 1; + } + +Key_Length_Specification XTS_Mode::key_spec() const + { + return cipher().key_spec().multiple(2); + } + +size_t XTS_Mode::default_nonce_length() const + { + return cipher().block_size(); + } + +bool XTS_Mode::valid_nonce_length(size_t n) const + { + return cipher().block_size() == n; + } + +void XTS_Mode::key_schedule(const byte key[], size_t length) + { + const size_t key_half = length / 2; + + if(length % 2 == 1 || !m_cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), length); + + m_cipher->set_key(&key[0], key_half); + m_tweak_cipher->set_key(&key[key_half], key_half); + } + +secure_vector XTS_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + copy_mem(&m_tweak[0], nonce, nonce_len); + m_tweak_cipher->encrypt(&m_tweak[0]); + + update_tweak(0); + + return secure_vector(); + } + +void XTS_Mode::update_tweak(size_t which) + { + const size_t BS = m_tweak_cipher->block_size(); + + if(which > 0) + poly_double(&m_tweak[0], &m_tweak[(which-1)*BS], BS); + + const size_t blocks_in_tweak = update_granularity() / BS; + + for(size_t i = 1; i < blocks_in_tweak; ++i) + poly_double(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); + } + +size_t XTS_Encryption::output_length(size_t input_length) const + { + return round_up(input_length, cipher().block_size()); + } + +void XTS_Encryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + const size_t blocks_in_tweak = update_granularity() / BS; + + while(blocks) + { + const size_t to_proc = std::min(blocks, blocks_in_tweak); + const size_t to_proc_bytes = to_proc * BS; + + xor_buf(buf, tweak(), to_proc_bytes); + cipher().encrypt_n(buf, buf, to_proc); + xor_buf(buf, tweak(), to_proc_bytes); + + buf += to_proc * BS; + blocks -= to_proc; + + update_tweak(to_proc); + } + } + +void XTS_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input"); + + const size_t BS = cipher().block_size(); + + if(sz % BS == 0) + { + update(buffer, offset); + } + else + { + // steal ciphertext + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last, tweak(), BS); + cipher().encrypt(last); + xor_buf(last, tweak(), BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + xor_buf(last, tweak() + BS, BS); + cipher().encrypt(last); + xor_buf(last, tweak() + BS, BS); + + buffer += last; + } + } + +size_t XTS_Decryption::output_length(size_t input_length) const + { + // might be less + return input_length; + } + +void XTS_Decryption::update(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + const size_t blocks_in_tweak = update_granularity() / BS; + + while(blocks) + { + const size_t to_proc = std::min(blocks, blocks_in_tweak); + const size_t to_proc_bytes = to_proc * BS; + + xor_buf(buf, tweak(), to_proc_bytes); + cipher().decrypt_n(buf, buf, to_proc); + xor_buf(buf, tweak(), to_proc_bytes); + + buf += to_proc * BS; + blocks -= to_proc; + + update_tweak(to_proc); + } + } + +void XTS_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input"); + + const size_t BS = cipher().block_size(); + + if(sz % BS == 0) + { + update(buffer, offset); + } + else + { + // steal ciphertext + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last, tweak() + BS, BS); + cipher().decrypt(last); + xor_buf(last, tweak() + BS, BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + xor_buf(last, tweak(), BS); + cipher().decrypt(last); + xor_buf(last, tweak(), BS); + + buffer += last; + } + } + +} diff --git a/src/lib/modes/xts/xts.h b/src/lib/modes/xts/xts.h new file mode 100644 index 000000000..21bc495e1 --- /dev/null +++ b/src/lib/modes/xts/xts.h @@ -0,0 +1,86 @@ +/* +* XTS mode, from IEEE P1619 +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODE_XTS_H__ +#define BOTAN_MODE_XTS_H__ + +#include +#include +#include + +namespace Botan { + +/** +* IEEE P1619 XTS Mode +*/ +class BOTAN_DLL XTS_Mode : public Cipher_Mode + { + public: + std::string name() const override; + + secure_vector start(const byte nonce[], size_t nonce_len) override; + + size_t update_granularity() const override; + + size_t minimum_final_size() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear(); + protected: + XTS_Mode(BlockCipher* cipher); + + const byte* tweak() const { return &m_tweak[0]; } + + const BlockCipher& cipher() const { return *m_cipher; } + + void update_tweak(size_t last_used); + + private: + void key_schedule(const byte key[], size_t length) override; + + std::unique_ptr m_cipher, m_tweak_cipher; + secure_vector m_tweak; + }; + +/** +* IEEE P1619 XTS Encryption +*/ +class BOTAN_DLL XTS_Encryption : public XTS_Mode + { + public: + XTS_Encryption(BlockCipher* cipher) : XTS_Mode(cipher) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + }; + +/** +* IEEE P1619 XTS Decryption +*/ +class BOTAN_DLL XTS_Decryption : public XTS_Mode + { + public: + XTS_Decryption(BlockCipher* cipher) : XTS_Mode(cipher) {} + + void update(secure_vector& blocks, size_t offset = 0) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + }; + +} + +#endif diff --git a/src/lib/passhash/bcrypt/bcrypt.cpp b/src/lib/passhash/bcrypt/bcrypt.cpp new file mode 100644 index 000000000..5ee75f4ed --- /dev/null +++ b/src/lib/passhash/bcrypt/bcrypt.cpp @@ -0,0 +1,150 @@ +/* +* Bcrypt Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string bcrypt_base64_encode(const byte input[], size_t length) + { + // Bcrypt uses a non-standard base64 alphabet + const byte OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39, + 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + std::string b64 = base64_encode(input, length); + + while(b64.size() && b64[b64.size()-1] == '=') + b64 = b64.substr(0, b64.size() - 1); + + for(size_t i = 0; i != b64.size(); ++i) + b64[i] = OPENBSD_BASE64_SUB[static_cast(b64[i])]; + + return b64; + } + +std::vector bcrypt_base64_decode(std::string input) + { + const byte OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + for(size_t i = 0; i != input.size(); ++i) + input[i] = OPENBSD_BASE64_SUB[static_cast(input[i])]; + + return unlock(base64_decode(input)); + } + +std::string make_bcrypt(const std::string& pass, + const std::vector& salt, + u16bit work_factor) + { + const byte magic[24] = { + 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, + 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74 + }; + + std::vector ctext(magic, magic + sizeof(magic)); + + Blowfish blowfish; + + // Include the trailing NULL byte + blowfish.eks_key_schedule(reinterpret_cast(pass.c_str()), + pass.length() + 1, + &salt[0], + work_factor); + + for(size_t i = 0; i != 64; ++i) + blowfish.encrypt_n(&ctext[0], &ctext[0], 3); + + std::string salt_b64 = bcrypt_base64_encode(&salt[0], salt.size()); + + std::string work_factor_str = std::to_string(work_factor); + if(work_factor_str.length() == 1) + work_factor_str = "0" + work_factor_str; + + return "$2a$" + work_factor_str + + "$" + salt_b64.substr(0, 22) + + bcrypt_base64_encode(&ctext[0], ctext.size() - 1); + } + +} + +std::string generate_bcrypt(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor) + { + return make_bcrypt(pass, unlock(rng.random_vec(16)), work_factor); + } + +bool check_bcrypt(const std::string& pass, const std::string& hash) + { + if(hash.size() != 60 || + hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' || + hash[3] != '$' || hash[6] != '$') + { + return false; + } + + const u16bit workfactor = to_u32bit(hash.substr(4, 2)); + + std::vector salt = bcrypt_base64_decode(hash.substr(7, 22)); + + const std::string compare = make_bcrypt(pass, salt, workfactor); + + return (hash == compare); + } + +} diff --git a/src/lib/passhash/bcrypt/bcrypt.h b/src/lib/passhash/bcrypt/bcrypt.h new file mode 100644 index 000000000..8a6ab58ea --- /dev/null +++ b/src/lib/passhash/bcrypt/bcrypt.h @@ -0,0 +1,37 @@ +/* +* Bcrypt Password Hashing +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BCRYPT_H__ +#define BOTAN_BCRYPT_H__ + +#include + +namespace Botan { + +/** +* Create a password hash using Bcrypt +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* +* @see http://www.usenix.org/events/usenix99/provos/provos_html/ +*/ +std::string BOTAN_DLL generate_bcrypt(const std::string& password, + RandomNumberGenerator& rng, + u16bit work_factor = 10); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_DLL check_bcrypt(const std::string& password, + const std::string& hash); + +} + +#endif diff --git a/src/lib/passhash/bcrypt/info.txt b/src/lib/passhash/bcrypt/info.txt new file mode 100644 index 000000000..5cc246cab --- /dev/null +++ b/src/lib/passhash/bcrypt/info.txt @@ -0,0 +1,9 @@ +define BCRYPT 20131128 + + +libstate +blowfish +rng +base64 + + diff --git a/src/lib/passhash/passhash9/info.txt b/src/lib/passhash/passhash9/info.txt new file mode 100644 index 000000000..f4af7fe0b --- /dev/null +++ b/src/lib/passhash/passhash9/info.txt @@ -0,0 +1,9 @@ +define PASSHASH9 20131128 + + +libstate +pbkdf2 +rng +base64 + + diff --git a/src/lib/passhash/passhash9/passhash9.cpp b/src/lib/passhash/passhash9/passhash9.cpp new file mode 100644 index 000000000..027ceeb76 --- /dev/null +++ b/src/lib/passhash/passhash9/passhash9.cpp @@ -0,0 +1,149 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const std::string MAGIC_PREFIX = "$9$"; + +const size_t WORKFACTOR_BYTES = 2; +const size_t ALGID_BYTES = 1; +const size_t SALT_BYTES = 12; // 96 bits of salt +const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output + +const size_t WORK_FACTOR_SCALE = 10000; + +MessageAuthenticationCode* get_pbkdf_prf(byte alg_id) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + try + { + if(alg_id == 0) + return af.make_mac("HMAC(SHA-1)"); + else if(alg_id == 1) + return af.make_mac("HMAC(SHA-256)"); + else if(alg_id == 2) + return af.make_mac("CMAC(Blowfish)"); + else if(alg_id == 3) + return af.make_mac("HMAC(SHA-384)"); + else if(alg_id == 4) + return af.make_mac("HMAC(SHA-512)"); + } + catch(Algorithm_Not_Found) {} + + return nullptr; + } + +} + +std::string generate_passhash9(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor, + byte alg_id) + { + MessageAuthenticationCode* prf = get_pbkdf_prf(alg_id); + + if(!prf) + throw Invalid_Argument("Passhash9: Algorithm id " + + std::to_string(alg_id) + + " is not defined"); + + PKCS5_PBKDF2 kdf(prf); // takes ownership of pointer + + secure_vector salt(SALT_BYTES); + rng.randomize(&salt[0], salt.size()); + + const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + secure_vector pbkdf2_output = + kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN, + pass, + &salt[0], salt.size(), + kdf_iterations).bits_of(); + + Pipe pipe(new Base64_Encoder); + pipe.start_msg(); + pipe.write(alg_id); + pipe.write(get_byte(0, work_factor)); + pipe.write(get_byte(1, work_factor)); + pipe.write(salt); + pipe.write(pbkdf2_output); + pipe.end_msg(); + + return MAGIC_PREFIX + pipe.read_all_as_string(); + } + +bool check_passhash9(const std::string& pass, const std::string& hash) + { + const size_t BINARY_LENGTH = + ALGID_BYTES + + WORKFACTOR_BYTES + + PASSHASH9_PBKDF_OUTPUT_LEN + + SALT_BYTES; + + const size_t BASE64_LENGTH = + MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6; + + if(hash.size() != BASE64_LENGTH) + return false; + + for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) + if(hash[i] != MAGIC_PREFIX[i]) + return false; + + Pipe pipe(new Base64_Decoder); + pipe.start_msg(); + pipe.write(hash.c_str() + MAGIC_PREFIX.size()); + pipe.end_msg(); + + secure_vector bin = pipe.read_all(); + + if(bin.size() != BINARY_LENGTH) + return false; + + byte alg_id = bin[0]; + + const size_t work_factor = load_be(&bin[ALGID_BYTES], 0); + + // Bug in the format, bad states shouldn't be representable, but are... + if(work_factor == 0) + return false; + + if(work_factor > 512) + throw std::invalid_argument("Requested Bcrypt work factor " + + std::to_string(work_factor) + " too large"); + + const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + MessageAuthenticationCode* pbkdf_prf = get_pbkdf_prf(alg_id); + + if(!pbkdf_prf) + return false; // unknown algorithm, reject + + PKCS5_PBKDF2 kdf(pbkdf_prf); // takes ownership of pointer + + secure_vector cmp = kdf.derive_key( + PASSHASH9_PBKDF_OUTPUT_LEN, + pass, + &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES, + kdf_iterations).bits_of(); + + return same_mem(&cmp[0], + &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES], + PASSHASH9_PBKDF_OUTPUT_LEN); + } + +} diff --git a/src/lib/passhash/passhash9/passhash9.h b/src/lib/passhash/passhash9/passhash9.h new file mode 100644 index 000000000..5fd0a1bf8 --- /dev/null +++ b/src/lib/passhash/passhash9/passhash9.h @@ -0,0 +1,43 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PASSHASH9_H__ +#define BOTAN_PASSHASH9_H__ + +#include + +namespace Botan { + +/** +* Create a password hash using PBKDF2 +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* @param alg_id specifies which PRF to use with PBKDF2 +* 0 is HMAC(SHA-1) +* 1 is HMAC(SHA-256) +* 2 is CMAC(Blowfish) +* 3 is HMAC(SHA-384) +* 4 is HMAC(SHA-512) +* all other values are currently undefined +*/ +std::string BOTAN_DLL generate_passhash9(const std::string& password, + RandomNumberGenerator& rng, + u16bit work_factor = 10, + byte alg_id = 1); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_DLL check_passhash9(const std::string& password, + const std::string& hash); + +} + +#endif diff --git a/src/lib/pbe/get_pbe.cpp b/src/lib/pbe/get_pbe.cpp new file mode 100644 index 000000000..4ec518776 --- /dev/null +++ b/src/lib/pbe/get_pbe.cpp @@ -0,0 +1,140 @@ +/* +* PBE Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_PBE_PKCS_V15) + #include +#endif + +#if defined(BOTAN_HAS_PBE_PKCS_V20) + #include + #include +#endif + +namespace Botan { + +/* +* Get an encryption PBE, set new parameters +*/ +PBE* get_pbe(const std::string& algo_spec, + const std::string& passphrase, + std::chrono::milliseconds msec, + RandomNumberGenerator& rng) + { + SCAN_Name request(algo_spec); + + const std::string pbe = request.algo_name(); + std::string digest_name = request.arg(0); + const std::string cipher = request.arg(1); + + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Invalid_Argument("PBE: Invalid cipher spec " + cipher); + + const std::string cipher_algo = SCAN_Name::deref_alias(cipher_spec[0]); + const std::string cipher_mode = cipher_spec[1]; + + if(cipher_mode != "CBC") + throw Invalid_Argument("PBE: Invalid cipher mode " + cipher); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo); + if(!block_cipher) + throw Algorithm_Not_Found(cipher_algo); + + const HashFunction* hash_function = af.prototype_hash_function(digest_name); + if(!hash_function) + throw Algorithm_Not_Found(digest_name); + + if(request.arg_count() != 2) + throw Invalid_Algorithm_Name(algo_spec); + +#if defined(BOTAN_HAS_PBE_PKCS_V15) + if(pbe == "PBE-PKCS5v15") + return new PBE_PKCS5v15(block_cipher->clone(), + hash_function->clone(), + passphrase, + msec, + rng); +#endif + +#if defined(BOTAN_HAS_PBE_PKCS_V20) + if(pbe == "PBE-PKCS5v20") + return new PBE_PKCS5v20(block_cipher->clone(), + new HMAC(hash_function->clone()), + passphrase, + msec, + rng); +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get a decryption PBE, decode parameters +*/ +PBE* get_pbe(const OID& pbe_oid, + const std::vector& params, + const std::string& passphrase) + { + SCAN_Name request(OIDS::lookup(pbe_oid)); + + const std::string pbe = request.algo_name(); + +#if defined(BOTAN_HAS_PBE_PKCS_V15) + if(pbe == "PBE-PKCS5v15") + { + if(request.arg_count() != 2) + throw Invalid_Algorithm_Name(request.as_string()); + + std::string digest_name = request.arg(0); + const std::string cipher = request.arg(1); + + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Invalid_Argument("PBE: Invalid cipher spec " + cipher); + + const std::string cipher_algo = SCAN_Name::deref_alias(cipher_spec[0]); + const std::string cipher_mode = cipher_spec[1]; + + if(cipher_mode != "CBC") + throw Invalid_Argument("PBE: Invalid cipher mode " + cipher); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo); + if(!block_cipher) + throw Algorithm_Not_Found(cipher_algo); + + const HashFunction* hash_function = + af.prototype_hash_function(digest_name); + + if(!hash_function) + throw Algorithm_Not_Found(digest_name); + + return new PBE_PKCS5v15(block_cipher->clone(), + hash_function->clone(), + params, + passphrase); + } +#endif + +#if defined(BOTAN_HAS_PBE_PKCS_V20) + if(pbe == "PBE-PKCS5v20") + return new PBE_PKCS5v20(params, passphrase); +#endif + + throw Algorithm_Not_Found(pbe_oid.as_string()); + } + +} diff --git a/src/lib/pbe/get_pbe.h b/src/lib/pbe/get_pbe.h new file mode 100644 index 000000000..df87c0547 --- /dev/null +++ b/src/lib/pbe/get_pbe.h @@ -0,0 +1,44 @@ +/* +* PBE Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LOOKUP_PBE_H__ +#define BOTAN_LOOKUP_PBE_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Factory function for PBEs. +* @param algo_spec the name of the PBE algorithm to retrieve +* @param passphrase the passphrase to use for encryption +* @param msec how many milliseconds to run the PBKDF +* @param rng a random number generator +* @return pointer to a PBE with randomly created parameters +*/ +BOTAN_DLL PBE* get_pbe(const std::string& algo_spec, + const std::string& passphrase, + std::chrono::milliseconds msec, + RandomNumberGenerator& rng); + +/** +* Factory function for PBEs. +* @param pbe_oid the oid of the desired PBE +* @param params a DataSource providing the DER encoded parameters to use +* @param passphrase the passphrase to use for decryption +* @return pointer to the PBE with the specified parameters +*/ +BOTAN_DLL PBE* get_pbe(const OID& pbe_oid, + const std::vector& params, + const std::string& passphrase); + +} + +#endif diff --git a/src/lib/pbe/info.txt b/src/lib/pbe/info.txt new file mode 100644 index 000000000..0436c4efd --- /dev/null +++ b/src/lib/pbe/info.txt @@ -0,0 +1,7 @@ +define PASSWORD_BASED_ENCRYPTION 20131128 + + +filters +libstate +oid_lookup + diff --git a/src/lib/pbe/pbe.h b/src/lib/pbe/pbe.h new file mode 100644 index 000000000..45c98e2c8 --- /dev/null +++ b/src/lib/pbe/pbe.h @@ -0,0 +1,39 @@ +/* +* PBE +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBE_BASE_H__ +#define BOTAN_PBE_BASE_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Password Based Encryption (PBE) Filter. +*/ +class BOTAN_DLL PBE : public Filter + { + public: + /** + * DER encode the params (the number of iterations and the salt value) + * @return encoded params + */ + virtual std::vector encode_params() const = 0; + + /** + * Get this PBE's OID. + * @return object identifier + */ + virtual OID get_oid() const = 0; + }; + +} + +#endif diff --git a/src/lib/pbe/pbes1/info.txt b/src/lib/pbe/pbes1/info.txt new file mode 100644 index 000000000..36d26ecc9 --- /dev/null +++ b/src/lib/pbe/pbes1/info.txt @@ -0,0 +1,10 @@ +define PBE_PKCS_V15 20131128 + + +asn1 +block +cbc +filters +hash +pbkdf1 + diff --git a/src/lib/pbe/pbes1/pbes1.cpp b/src/lib/pbe/pbes1/pbes1.cpp new file mode 100644 index 000000000..a30f10a6c --- /dev/null +++ b/src/lib/pbe/pbes1/pbes1.cpp @@ -0,0 +1,193 @@ +/* +* PKCS #5 PBES1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Encrypt some bytes using PBES1 +*/ +void PBE_PKCS5v15::write(const byte input[], size_t length) + { + m_pipe.write(input, length); + flush_pipe(true); + } + +/* +* Start encrypting with PBES1 +*/ +void PBE_PKCS5v15::start_msg() + { + m_pipe.append(get_cipher(m_block_cipher->name() + "/CBC/PKCS7", + m_key, m_iv, m_direction)); + + m_pipe.start_msg(); + if(m_pipe.message_count() > 1) + m_pipe.set_default_msg(m_pipe.default_msg() + 1); + } + +/* +* Finish encrypting with PBES1 +*/ +void PBE_PKCS5v15::end_msg() + { + m_pipe.end_msg(); + flush_pipe(false); + m_pipe.reset(); + } + +/* +* Flush the pipe +*/ +void PBE_PKCS5v15::flush_pipe(bool safe_to_skip) + { + if(safe_to_skip && m_pipe.remaining() < 64) + return; + + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(m_pipe.remaining()) + { + size_t got = m_pipe.read(&buffer[0], buffer.size()); + send(buffer, got); + } + } + +/* +* Encode PKCS#5 PBES1 parameters +*/ +std::vector PBE_PKCS5v15::encode_params() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(m_salt, OCTET_STRING) + .encode(m_iterations) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Return an OID for this PBES1 type +*/ +OID PBE_PKCS5v15::get_oid() const + { + const OID base_pbes1_oid("1.2.840.113549.1.5"); + + const std::string cipher = m_block_cipher->name(); + const std::string digest = m_hash_function->name(); + + if(cipher == "DES" && digest == "MD2") + return (base_pbes1_oid + 1); + else if(cipher == "DES" && digest == "MD5") + return (base_pbes1_oid + 3); + else if(cipher == "DES" && digest == "SHA-160") + return (base_pbes1_oid + 10); + else if(cipher == "RC2" && digest == "MD2") + return (base_pbes1_oid + 4); + else if(cipher == "RC2" && digest == "MD5") + return (base_pbes1_oid + 6); + else if(cipher == "RC2" && digest == "SHA-160") + return (base_pbes1_oid + 11); + else + throw Internal_Error("PBE-PKCS5 v1.5: get_oid() has run out of options"); + } + +std::string PBE_PKCS5v15::name() const + { + return "PBE-PKCS5v15(" + m_block_cipher->name() + "," + + m_hash_function->name() + ")"; + } + +PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher, + HashFunction* hash, + const std::string& passphrase, + std::chrono::milliseconds msec, + RandomNumberGenerator& rng) : + m_direction(ENCRYPTION), + m_block_cipher(cipher), + m_hash_function(hash), + m_salt(rng.random_vec(8)) + { + if(cipher->name() != "DES" && cipher->name() != "RC2") + { + throw Invalid_Argument("PBE_PKCS5v1.5: Unknown cipher " + + cipher->name()); + } + + if(hash->name() != "MD2" && hash->name() != "MD5" && + hash->name() != "SHA-160") + { + throw Invalid_Argument("PBE_PKCS5v1.5: Unknown hash " + + hash->name()); + } + + PKCS5_PBKDF1 pbkdf(m_hash_function->clone()); + + secure_vector key_and_iv = + pbkdf.derive_key(16, passphrase, + &m_salt[0], m_salt.size(), + msec, m_iterations).bits_of(); + + m_key.assign(&key_and_iv[0], &key_and_iv[8]); + m_iv.assign(&key_and_iv[8], &key_and_iv[16]); + + } + +PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher, + HashFunction* hash, + const std::vector& params, + const std::string& passphrase) : + m_direction(DECRYPTION), + m_block_cipher(cipher), + m_hash_function(hash) + { + if(cipher->name() != "DES" && cipher->name() != "RC2") + { + throw Invalid_Argument("PBE_PKCS5v1.5: Unknown cipher " + + cipher->name()); + } + + if(hash->name() != "MD2" && hash->name() != "MD5" && + hash->name() != "SHA-160") + { + throw Invalid_Argument("PBE_PKCS5v1.5: Unknown hash " + + hash->name()); + } + + BER_Decoder(params) + .start_cons(SEQUENCE) + .decode(m_salt, OCTET_STRING) + .decode(m_iterations) + .verify_end() + .end_cons(); + + if(m_salt.size() != 8) + throw Decoding_Error("PBES1: Encoded salt is not 8 octets"); + + PKCS5_PBKDF1 pbkdf(m_hash_function->clone()); + + secure_vector key_and_iv = + pbkdf.derive_key(16, passphrase, + &m_salt[0], m_salt.size(), + m_iterations).bits_of(); + + m_key.assign(&key_and_iv[0], &key_and_iv[8]); + m_iv.assign(&key_and_iv[8], &key_and_iv[16]); + } + +PBE_PKCS5v15::~PBE_PKCS5v15() + { + delete m_block_cipher; + delete m_hash_function; + } + +} diff --git a/src/lib/pbe/pbes1/pbes1.h b/src/lib/pbe/pbes1/pbes1.h new file mode 100644 index 000000000..8d1a6f877 --- /dev/null +++ b/src/lib/pbe/pbes1/pbes1.h @@ -0,0 +1,69 @@ +/* +* PKCS #5 v1.5 PBE +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBE_PKCS_V15_H__ +#define BOTAN_PBE_PKCS_V15_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* PKCS #5 v1.5 PBE +*/ +class BOTAN_DLL PBE_PKCS5v15 : public PBE + { + public: + OID get_oid() const; + + std::vector encode_params() const; + + std::string name() const; + + void write(const byte[], size_t); + void start_msg(); + void end_msg(); + + /** + * @param cipher the block cipher to use (DES or RC2) + * @param hash the hash function to use + * @param passphrase the passphrase to use + * @param msec how many milliseconds to run the PBKDF + * @param rng a random number generator + */ + PBE_PKCS5v15(BlockCipher* cipher, + HashFunction* hash, + const std::string& passphrase, + std::chrono::milliseconds msec, + RandomNumberGenerator& rng); + + PBE_PKCS5v15(BlockCipher* cipher, + HashFunction* hash, + const std::vector& params, + const std::string& passphrase); + + ~PBE_PKCS5v15(); + private: + + void flush_pipe(bool); + + Cipher_Dir m_direction; + BlockCipher* m_block_cipher; + HashFunction* m_hash_function; + + secure_vector m_salt, m_key, m_iv; + size_t m_iterations; + Pipe m_pipe; + }; + +} + +#endif diff --git a/src/lib/pbe/pbes2/info.txt b/src/lib/pbe/pbes2/info.txt new file mode 100644 index 000000000..ba7d77774 --- /dev/null +++ b/src/lib/pbe/pbes2/info.txt @@ -0,0 +1,14 @@ +define PBE_PKCS_V20 20131128 + + +algo_factory +asn1 +block +cbc +filters +hash +hmac +libstate +oid_lookup +pbkdf2 + diff --git a/src/lib/pbe/pbes2/pbes2.cpp b/src/lib/pbe/pbes2/pbes2.cpp new file mode 100644 index 000000000..d4df1277c --- /dev/null +++ b/src/lib/pbe/pbes2/pbes2.cpp @@ -0,0 +1,209 @@ +/* +* PKCS #5 PBES2 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Encrypt some bytes using PBES2 +*/ +void PBE_PKCS5v20::write(const byte input[], size_t length) + { + pipe.write(input, length); + flush_pipe(true); + } + +/* +* Start encrypting with PBES2 +*/ +void PBE_PKCS5v20::start_msg() + { + pipe.append(get_cipher(block_cipher->name() + "/CBC/PKCS7", + key, iv, direction)); + + pipe.start_msg(); + if(pipe.message_count() > 1) + pipe.set_default_msg(pipe.default_msg() + 1); + } + +/* +* Finish encrypting with PBES2 +*/ +void PBE_PKCS5v20::end_msg() + { + pipe.end_msg(); + flush_pipe(false); + pipe.reset(); + } + +/* +* Flush the pipe +*/ +void PBE_PKCS5v20::flush_pipe(bool safe_to_skip) + { + if(safe_to_skip && pipe.remaining() < 64) + return; + + secure_vector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + const size_t got = pipe.read(&buffer[0], buffer.size()); + send(buffer, got); + } + } + +/* +* Encode PKCS#5 PBES2 parameters +*/ +std::vector PBE_PKCS5v20::encode_params() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode( + AlgorithmIdentifier("PKCS5.PBKDF2", + DER_Encoder() + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(iterations) + .encode(key_length) + .encode_if( + m_prf->name() != "HMAC(SHA-160)", + AlgorithmIdentifier(m_prf->name(), + AlgorithmIdentifier::USE_NULL_PARAM)) + .end_cons() + .get_contents_unlocked() + ) + ) + .encode( + AlgorithmIdentifier(block_cipher->name() + "/CBC", + DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked() + ) + ) + .end_cons() + .get_contents_unlocked(); + } + +/* +* Return an OID for PBES2 +*/ +OID PBE_PKCS5v20::get_oid() const + { + return OIDS::lookup("PBE-PKCS5v20"); + } + +std::string PBE_PKCS5v20::name() const + { + return "PBE-PKCS5v20(" + block_cipher->name() + "," + + m_prf->name() + ")"; + } + +/* +* PKCS#5 v2.0 PBE Constructor +*/ +PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher, + MessageAuthenticationCode* mac, + const std::string& passphrase, + std::chrono::milliseconds msec, + RandomNumberGenerator& rng) : + direction(ENCRYPTION), + block_cipher(cipher), + m_prf(mac), + salt(rng.random_vec(12)), + iv(rng.random_vec(block_cipher->block_size())), + iterations(0), + key_length(block_cipher->maximum_keylength()) + { + PKCS5_PBKDF2 pbkdf(m_prf->clone()); + + key = pbkdf.derive_key(key_length, passphrase, + &salt[0], salt.size(), + msec, iterations).bits_of(); + } + +/* +* PKCS#5 v2.0 PBE Constructor +*/ +PBE_PKCS5v20::PBE_PKCS5v20(const std::vector& params, + const std::string& passphrase) : + direction(DECRYPTION), + block_cipher(nullptr), + m_prf(nullptr) + { + AlgorithmIdentifier kdf_algo, enc_algo; + + BER_Decoder(params) + .start_cons(SEQUENCE) + .decode(kdf_algo) + .decode(enc_algo) + .verify_end() + .end_cons(); + + AlgorithmIdentifier prf_algo; + + if(kdf_algo.oid != OIDS::lookup("PKCS5.PBKDF2")) + throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + + kdf_algo.oid.as_string()); + + BER_Decoder(kdf_algo.parameters) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(iterations) + .decode_optional(key_length, INTEGER, UNIVERSAL) + .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED, + AlgorithmIdentifier("HMAC(SHA-160)", + AlgorithmIdentifier::USE_NULL_PARAM)) + .verify_end() + .end_cons(); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + std::string cipher = OIDS::lookup(enc_algo.oid); + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + + if(cipher_spec[1] != "CBC") + throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + + cipher); + + BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end(); + + block_cipher = af.make_block_cipher(cipher_spec[0]); + m_prf = af.make_mac(OIDS::lookup(prf_algo.oid)); + + if(key_length == 0) + key_length = block_cipher->maximum_keylength(); + + if(salt.size() < 8) + throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); + + PKCS5_PBKDF2 pbkdf(m_prf->clone()); + + key = pbkdf.derive_key(key_length, passphrase, + &salt[0], salt.size(), + iterations).bits_of(); + } + +PBE_PKCS5v20::~PBE_PKCS5v20() + { + delete m_prf; + delete block_cipher; + } + +} diff --git a/src/lib/pbe/pbes2/pbes2.h b/src/lib/pbe/pbes2/pbes2.h new file mode 100644 index 000000000..b7160f575 --- /dev/null +++ b/src/lib/pbe/pbes2/pbes2.h @@ -0,0 +1,70 @@ +/* +* PKCS #5 v2.0 PBE +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBE_PKCS_v20_H__ +#define BOTAN_PBE_PKCS_v20_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* PKCS #5 v2.0 PBE +*/ +class BOTAN_DLL PBE_PKCS5v20 : public PBE + { + public: + OID get_oid() const; + + std::vector encode_params() const; + + std::string name() const; + + void write(const byte buf[], size_t buf_len); + void start_msg(); + void end_msg(); + + /** + * Load a PKCS #5 v2.0 encrypted stream + * @param params the PBES2 parameters + * @param passphrase the passphrase to use for decryption + */ + PBE_PKCS5v20(const std::vector& params, + const std::string& passphrase); + + /** + * @param cipher the block cipher to use + * @param mac the MAC to use + * @param passphrase the passphrase to use for encryption + * @param msec how many milliseconds to run the PBKDF + * @param rng a random number generator + */ + PBE_PKCS5v20(BlockCipher* cipher, + MessageAuthenticationCode* mac, + const std::string& passphrase, + std::chrono::milliseconds msec, + RandomNumberGenerator& rng); + + ~PBE_PKCS5v20(); + private: + void flush_pipe(bool); + + Cipher_Dir direction; + BlockCipher* block_cipher; + MessageAuthenticationCode* m_prf; + secure_vector salt, key, iv; + size_t iterations, key_length; + Pipe pipe; + }; + +} + +#endif diff --git a/src/lib/pbkdf/info.txt b/src/lib/pbkdf/info.txt new file mode 100644 index 000000000..d991577f7 --- /dev/null +++ b/src/lib/pbkdf/info.txt @@ -0,0 +1,3 @@ + +algo_base + diff --git a/src/lib/pbkdf/pbkdf.cpp b/src/lib/pbkdf/pbkdf.cpp new file mode 100644 index 000000000..ccd203dbd --- /dev/null +++ b/src/lib/pbkdf/pbkdf.cpp @@ -0,0 +1,44 @@ +/* +* PBKDF +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +OctetString PBKDF::derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const + { + if(iterations == 0) + throw std::invalid_argument(name() + ": Invalid iteration count"); + + auto derived = key_derivation(output_len, passphrase, + salt, salt_len, iterations, + std::chrono::milliseconds(0)); + + BOTAN_ASSERT(derived.first == iterations, + "PBKDF used the correct number of iterations"); + + return derived.second; + } + +OctetString PBKDF::derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + std::chrono::milliseconds ms, + size_t& iterations) const + { + auto derived = key_derivation(output_len, passphrase, salt, salt_len, 0, ms); + + iterations = derived.first; + + return derived.second; + } + +} diff --git a/src/lib/pbkdf/pbkdf.h b/src/lib/pbkdf/pbkdf.h new file mode 100644 index 000000000..65ad8e83a --- /dev/null +++ b/src/lib/pbkdf/pbkdf.h @@ -0,0 +1,124 @@ +/* +* PBKDF +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBKDF_H__ +#define BOTAN_PBKDF_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Base class for PBKDF (password based key derivation function) +* implementations. Converts a password into a key using a salt +* and iterated hashing to make brute force attacks harder. +*/ +class BOTAN_DLL PBKDF : public Algorithm + { + public: + + /** + * @return new instance of this same algorithm + */ + virtual PBKDF* clone() const = 0; + + void clear() {} + + /** + * Derive a key from a passphrase + * @param output_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + */ + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const; + + /** + * Derive a key from a passphrase + * @param output_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param iterations the number of iterations to use (use 10K or more) + */ + template + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const std::vector& salt, + size_t iterations) const + { + return derive_key(output_len, passphrase, &salt[0], salt.size(), iterations); + } + + /** + * Derive a key from a passphrase + * @param output_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec is how long to run the PBKDF + * @param iterations is set to the number of iterations used + */ + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + /** + * Derive a key from a passphrase using a certain amount of time + * @param output_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param msec is how long to run the PBKDF + * @param iterations is set to the number of iterations used + */ + template + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const std::vector& salt, + std::chrono::milliseconds msec, + size_t& iterations) const + { + return derive_key(output_len, passphrase, &salt[0], salt.size(), msec, iterations); + } + + /** + * Derive a key from a passphrase for a number of iterations + * specified by either iterations or if iterations == 0 then + * running until seconds time has elapsed. + * + * @param output_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @return the number of iterations performed and the derived key + */ + virtual std::pair + key_derivation(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const = 0; + }; + +/** +* For compatability with 1.8 +*/ +typedef PBKDF S2K; + +} + +#endif diff --git a/src/lib/pbkdf/pbkdf1/info.txt b/src/lib/pbkdf/pbkdf1/info.txt new file mode 100644 index 000000000..1ec626cac --- /dev/null +++ b/src/lib/pbkdf/pbkdf1/info.txt @@ -0,0 +1,5 @@ +define PBKDF1 20131128 + + +hash + diff --git a/src/lib/pbkdf/pbkdf1/pbkdf1.cpp b/src/lib/pbkdf/pbkdf1/pbkdf1.cpp new file mode 100644 index 000000000..9d1672529 --- /dev/null +++ b/src/lib/pbkdf/pbkdf1/pbkdf1.cpp @@ -0,0 +1,58 @@ +/* +* PBKDF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Return a PKCS#5 PBKDF1 derived key +*/ +std::pair +PKCS5_PBKDF1::key_derivation(size_t key_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + if(key_len > hash->output_length()) + throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long"); + + hash->update(passphrase); + hash->update(salt, salt_len); + secure_vector key = hash->final(); + + const auto start = std::chrono::high_resolution_clock::now(); + size_t iterations_performed = 1; + + while(true) + { + if(iterations == 0) + { + if(iterations_performed % 10000 == 0) + { + auto time_taken = std::chrono::high_resolution_clock::now() - start; + auto msec_taken = std::chrono::duration_cast(time_taken); + if(msec_taken > msec) + break; + } + } + else if(iterations_performed == iterations) + break; + + hash->update(key); + hash->final(&key[0]); + + ++iterations_performed; + } + + return std::make_pair(iterations_performed, + OctetString(&key[0], std::min(key_len, key.size()))); + } + +} diff --git a/src/lib/pbkdf/pbkdf1/pbkdf1.h b/src/lib/pbkdf/pbkdf1/pbkdf1.h new file mode 100644 index 000000000..783b70ed9 --- /dev/null +++ b/src/lib/pbkdf/pbkdf1/pbkdf1.h @@ -0,0 +1,61 @@ +/* +* PBKDF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBKDF1_H__ +#define BOTAN_PBKDF1_H__ + +#include +#include + +namespace Botan { + +/** +* PKCS #5 v1 PBKDF, aka PBKDF1 +* Can only generate a key up to the size of the hash output. +* Unless needed for backwards compatability, use PKCS5_PBKDF2 +*/ +class BOTAN_DLL PKCS5_PBKDF1 : public PBKDF + { + public: + /** + * Create a PKCS #5 instance using the specified hash function. + * @param hash_in pointer to a hash function object to use + */ + PKCS5_PBKDF1(HashFunction* hash_in) : hash(hash_in) {} + + /** + * Copy constructor + * @param other the object to copy + */ + PKCS5_PBKDF1(const PKCS5_PBKDF1& other) : + PBKDF(), hash(other.hash->clone()) {} + + ~PKCS5_PBKDF1() { delete hash; } + + std::string name() const + { + return "PBKDF1(" + hash->name() + ")"; + } + + PBKDF* clone() const + { + return new PKCS5_PBKDF1(hash->clone()); + } + + std::pair + key_derivation(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const override; + private: + HashFunction* hash; + }; + +} + +#endif diff --git a/src/lib/pbkdf/pbkdf2/info.txt b/src/lib/pbkdf/pbkdf2/info.txt new file mode 100644 index 000000000..b13168c53 --- /dev/null +++ b/src/lib/pbkdf/pbkdf2/info.txt @@ -0,0 +1,5 @@ +define PBKDF2 20131128 + + +mac + diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp new file mode 100644 index 000000000..c24bcaff8 --- /dev/null +++ b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp @@ -0,0 +1,111 @@ +/* +* PBKDF2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Return a PKCS #5 PBKDF2 derived key +*/ +std::pair +PKCS5_PBKDF2::key_derivation(size_t key_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + if(key_len == 0) + return std::make_pair(iterations, OctetString()); + + try + { + mac->set_key(reinterpret_cast(passphrase.data()), + passphrase.length()); + } + catch(Invalid_Key_Length) + { + throw Exception(name() + " cannot accept passphrases of length " + + std::to_string(passphrase.length())); + } + + secure_vector key(key_len); + + byte* T = &key[0]; + + secure_vector U(mac->output_length()); + + const size_t blocks_needed = round_up(key_len, mac->output_length()) / mac->output_length(); + + std::chrono::microseconds usec_per_block = + std::chrono::duration_cast(msec) / blocks_needed; + + u32bit counter = 1; + while(key_len) + { + size_t T_size = std::min(mac->output_length(), key_len); + + mac->update(salt, salt_len); + mac->update_be(counter); + mac->final(&U[0]); + + xor_buf(T, &U[0], T_size); + + if(iterations == 0) + { + /* + If no iterations set, run the first block to calibrate based + on how long hashing takes on whatever machine we're running on. + */ + + const auto start = std::chrono::high_resolution_clock::now(); + + iterations = 1; // the first iteration we did above + + while(true) + { + mac->update(U); + mac->final(&U[0]); + xor_buf(T, &U[0], T_size); + iterations++; + + /* + Only break on relatively 'even' iterations. For one it + avoids confusion, and likely some broken implementations + break on getting completely randomly distributed values + */ + if(iterations % 10000 == 0) + { + auto time_taken = std::chrono::high_resolution_clock::now() - start; + auto usec_taken = std::chrono::duration_cast(time_taken); + if(usec_taken > usec_per_block) + break; + } + } + } + else + { + for(size_t i = 1; i != iterations; ++i) + { + mac->update(U); + mac->final(&U[0]); + xor_buf(T, &U[0], T_size); + } + } + + key_len -= T_size; + T += T_size; + ++counter; + } + + return std::make_pair(iterations, key); + } + +} diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.h b/src/lib/pbkdf/pbkdf2/pbkdf2.h new file mode 100644 index 000000000..8bc271fcf --- /dev/null +++ b/src/lib/pbkdf/pbkdf2/pbkdf2.h @@ -0,0 +1,55 @@ +/* +* PBKDF2 +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBKDF2_H__ +#define BOTAN_PBKDF2_H__ + +#include +#include + +namespace Botan { + +/** +* PKCS #5 PBKDF2 +*/ +class BOTAN_DLL PKCS5_PBKDF2 : public PBKDF + { + public: + std::string name() const override + { + return "PBKDF2(" + mac->name() + ")"; + } + + PBKDF* clone() const override + { + return new PKCS5_PBKDF2(mac->clone()); + } + + std::pair + key_derivation(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const override; + + /** + * Create a PKCS #5 instance using the specified message auth code + * @param mac_fn the MAC to use + */ + PKCS5_PBKDF2(MessageAuthenticationCode* mac_fn) : mac(mac_fn) {} + + /** + * Destructor + */ + ~PKCS5_PBKDF2() { delete mac; } + private: + MessageAuthenticationCode* mac; + }; + +} + +#endif diff --git a/src/lib/pk_pad/eme.cpp b/src/lib/pk_pad/eme.cpp new file mode 100644 index 000000000..f90239d8c --- /dev/null +++ b/src/lib/pk_pad/eme.cpp @@ -0,0 +1,50 @@ +/* +* EME Base Class +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Encode a message +*/ +secure_vector EME::encode(const byte msg[], size_t msg_len, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(msg, msg_len, key_bits, rng); + } + +/* +* Encode a message +*/ +secure_vector EME::encode(const secure_vector& msg, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(&msg[0], msg.size(), key_bits, rng); + } + +/* +* Decode a message +*/ +secure_vector EME::decode(const byte msg[], size_t msg_len, + size_t key_bits) const + { + return unpad(msg, msg_len, key_bits); + } + +/* +* Decode a message +*/ +secure_vector EME::decode(const secure_vector& msg, + size_t key_bits) const + { + return unpad(&msg[0], msg.size(), key_bits); + } + +} diff --git a/src/lib/pk_pad/eme.h b/src/lib/pk_pad/eme.h new file mode 100644 index 000000000..358b4f144 --- /dev/null +++ b/src/lib/pk_pad/eme.h @@ -0,0 +1,109 @@ +/* +* EME Classes +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PUBKEY_EME_ENCRYPTION_PAD_H__ +#define BOTAN_PUBKEY_EME_ENCRYPTION_PAD_H__ + +#include +#include + +namespace Botan { + +/** +* Encoding Method for Encryption +*/ +class BOTAN_DLL EME + { + public: + /** + * Return the maximum input size in bytes we can support + * @param keybits the size of the key in bits + * @return upper bound of input in bytes + */ + virtual size_t maximum_input_size(size_t keybits) const = 0; + + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + secure_vector encode(const byte in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Encode an input + * @param in the plaintext + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + secure_vector encode(const secure_vector& in, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Decode an input + * @param in the encoded plaintext + * @param in_length length of encoded plaintext in bytes + * @param key_length length of the key in bits + * @return plaintext + */ + secure_vector decode(const byte in[], + size_t in_length, + size_t key_length) const; + + /** + * Decode an input + * @param in the encoded plaintext + * @param key_length length of the key in bits + * @return plaintext + */ + secure_vector decode(const secure_vector& in, + size_t key_length) const; + + virtual ~EME() {} + private: + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + virtual secure_vector pad(const byte in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const = 0; + + /** + * Decode an input + * @param in the encoded plaintext + * @param in_length length of encoded plaintext in bytes + * @param key_length length of the key in bits + * @return plaintext + */ + virtual secure_vector unpad(const byte in[], + size_t in_length, + size_t key_length) const = 0; + }; + +/** +* Factory method for EME (message-encoding methods for encryption) objects +* @param algo_spec the name of the EME to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL EME* get_eme(const std::string& algo_spec); + +} + +#endif diff --git a/src/lib/pk_pad/eme1/eme1.cpp b/src/lib/pk_pad/eme1/eme1.cpp new file mode 100644 index 000000000..dadb44d0a --- /dev/null +++ b/src/lib/pk_pad/eme1/eme1.cpp @@ -0,0 +1,130 @@ +/* +* EME1 (aka OAEP) +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* EME1 Pad Operation +*/ +secure_vector EME1::pad(const byte in[], size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const + { + key_length /= 8; + + if(key_length < in_length + 2*Phash.size() + 1) + throw Invalid_Argument("EME1: Input is too large"); + + secure_vector out(key_length); + + rng.randomize(&out[0], Phash.size()); + + buffer_insert(out, Phash.size(), &Phash[0], Phash.size()); + out[out.size() - in_length - 1] = 0x01; + buffer_insert(out, out.size() - in_length, in, in_length); + + mgf->mask(&out[0], Phash.size(), + &out[Phash.size()], out.size() - Phash.size()); + + mgf->mask(&out[Phash.size()], out.size() - Phash.size(), + &out[0], Phash.size()); + + return out; + } + +/* +* EME1 Unpad Operation +*/ +secure_vector EME1::unpad(const byte in[], size_t in_length, + size_t key_length) const + { + /* + Must be careful about error messages here; if an attacker can + distinguish them, it is easy to use the differences as an oracle to + find the secret key, as described in "A Chosen Ciphertext Attack on + RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in + PKCS #1 v2.0", James Manger, Crypto 2001 + + Also have to be careful about timing attacks! Pointed out by Falko + Strenzke. + */ + + key_length /= 8; + + // Invalid input: truncate to zero length input, causing later + // checks to fail + if(in_length > key_length) + in_length = 0; + + secure_vector input(key_length); + buffer_insert(input, key_length - in_length, in, in_length); + + mgf->mask(&input[Phash.size()], input.size() - Phash.size(), + &input[0], Phash.size()); + mgf->mask(&input[0], Phash.size(), + &input[Phash.size()], input.size() - Phash.size()); + + bool waiting_for_delim = true; + bool bad_input = false; + size_t delim_idx = 2 * Phash.size(); + + /* + * GCC 4.5 on x86-64 compiles this in a way that is still vunerable + * to timing analysis. Other compilers, or GCC on other platforms, + * may or may not. + */ + for(size_t i = delim_idx; i < input.size(); ++i) + { + const bool zero_p = !input[i]; + const bool one_p = input[i] == 0x01; + + const bool add_1 = waiting_for_delim && zero_p; + + bad_input |= waiting_for_delim && !(zero_p || one_p); + + delim_idx += add_1; + + waiting_for_delim &= zero_p; + } + + // If we never saw any non-zero byte, then it's not valid input + bad_input |= waiting_for_delim; + + bad_input |= !same_mem(&input[Phash.size()], &Phash[0], Phash.size()); + + if(bad_input) + throw Decoding_Error("Invalid EME1 encoding"); + + return secure_vector(&input[delim_idx + 1], &input[input.size()]); + } + +/* +* Return the max input size for a given key size +*/ +size_t EME1::maximum_input_size(size_t keybits) const + { + if(keybits / 8 > 2*Phash.size() + 1) + return ((keybits / 8) - 2*Phash.size() - 1); + else + return 0; + } + +/* +* EME1 Constructor +*/ +EME1::EME1(HashFunction* hash, const std::string& P) + { + Phash = hash->process(P); + mgf = new MGF1(hash); + } + +} diff --git a/src/lib/pk_pad/eme1/eme1.h b/src/lib/pk_pad/eme1/eme1.h new file mode 100644 index 000000000..eb6fc6bf5 --- /dev/null +++ b/src/lib/pk_pad/eme1/eme1.h @@ -0,0 +1,43 @@ +/* +* EME1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EME1_H__ +#define BOTAN_EME1_H__ + +#include +#include +#include + +namespace Botan { + +/** +* EME1, aka OAEP +*/ +class BOTAN_DLL EME1 : public EME + { + public: + size_t maximum_input_size(size_t) const; + + /** + * @param hash object to use for hashing (takes ownership) + * @param P an optional label. Normally empty. + */ + EME1(HashFunction* hash, const std::string& P = ""); + + ~EME1() { delete mgf; } + private: + secure_vector pad(const byte[], size_t, size_t, + RandomNumberGenerator&) const; + secure_vector unpad(const byte[], size_t, size_t) const; + + secure_vector Phash; + MGF* mgf; + }; + +} + +#endif diff --git a/src/lib/pk_pad/eme1/info.txt b/src/lib/pk_pad/eme1/info.txt new file mode 100644 index 000000000..7e911f495 --- /dev/null +++ b/src/lib/pk_pad/eme1/info.txt @@ -0,0 +1,9 @@ +define EME1 20131128 + +load_on auto + + +hash +kdf +mgf1 + diff --git a/src/lib/pk_pad/eme_pkcs/eme_pkcs.cpp b/src/lib/pk_pad/eme_pkcs/eme_pkcs.cpp new file mode 100644 index 000000000..0e7d1fc30 --- /dev/null +++ b/src/lib/pk_pad/eme_pkcs/eme_pkcs.cpp @@ -0,0 +1,70 @@ +/* +* PKCS1 EME +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* PKCS1 Pad Operation +*/ +secure_vector EME_PKCS1v15::pad(const byte in[], size_t inlen, + size_t olen, + RandomNumberGenerator& rng) const + { + olen /= 8; + + if(olen < 10) + throw Encoding_Error("PKCS1: Output space too small"); + if(inlen > olen - 10) + throw Encoding_Error("PKCS1: Input is too large"); + + secure_vector out(olen); + + out[0] = 0x02; + for(size_t j = 1; j != olen - inlen - 1; ++j) + while(out[j] == 0) + out[j] = rng.next_byte(); + buffer_insert(out, olen - inlen, in, inlen); + + return out; + } + +/* +* PKCS1 Unpad Operation +*/ +secure_vector EME_PKCS1v15::unpad(const byte in[], size_t inlen, + size_t key_len) const + { + if(inlen != key_len / 8 || inlen < 10 || in[0] != 0x02) + throw Decoding_Error("PKCS1::unpad"); + + size_t seperator = 0; + for(size_t j = 0; j != inlen; ++j) + if(in[j] == 0) + { + seperator = j; + break; + } + if(seperator < 9) + throw Decoding_Error("PKCS1::unpad"); + + return secure_vector(&in[seperator + 1], &in[inlen]); + } + +/* +* Return the max input size for a given key size +*/ +size_t EME_PKCS1v15::maximum_input_size(size_t keybits) const + { + if(keybits / 8 > 10) + return ((keybits / 8) - 10); + else + return 0; + } + +} diff --git a/src/lib/pk_pad/eme_pkcs/eme_pkcs.h b/src/lib/pk_pad/eme_pkcs/eme_pkcs.h new file mode 100644 index 000000000..2808e18d6 --- /dev/null +++ b/src/lib/pk_pad/eme_pkcs/eme_pkcs.h @@ -0,0 +1,30 @@ +/* +* EME PKCS#1 v1.5 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EME_PKCS1_H__ +#define BOTAN_EME_PKCS1_H__ + +#include + +namespace Botan { + +/** +* EME from PKCS #1 v1.5 +*/ +class BOTAN_DLL EME_PKCS1v15 : public EME + { + public: + size_t maximum_input_size(size_t) const; + private: + secure_vector pad(const byte[], size_t, size_t, + RandomNumberGenerator&) const; + secure_vector unpad(const byte[], size_t, size_t) const; + }; + +} + +#endif diff --git a/src/lib/pk_pad/eme_pkcs/info.txt b/src/lib/pk_pad/eme_pkcs/info.txt new file mode 100644 index 000000000..432aaf8eb --- /dev/null +++ b/src/lib/pk_pad/eme_pkcs/info.txt @@ -0,0 +1 @@ +define EME_PKCS1v15 20131128 diff --git a/src/lib/pk_pad/emsa.h b/src/lib/pk_pad/emsa.h new file mode 100644 index 000000000..5db01ec12 --- /dev/null +++ b/src/lib/pk_pad/emsa.h @@ -0,0 +1,68 @@ +/* +* EMSA Classes +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PUBKEY_EMSA_H__ +#define BOTAN_PUBKEY_EMSA_H__ + +#include +#include + +namespace Botan { + +/** +* Encoding Method for Signatures, Appendix +*/ +class BOTAN_DLL EMSA + { + public: + /** + * Add more data to the signature computation + * @param input some data + * @param length length of input in bytes + */ + virtual void update(const byte input[], size_t length) = 0; + + /** + * @return raw hash + */ + virtual secure_vector raw_data() = 0; + + /** + * Return the encoding of a message + * @param msg the result of raw_data() + * @param output_bits the desired output bit size + * @param rng a random number generator + * @return encoded signature + */ + virtual secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) = 0; + + /** + * Verify the encoding + * @param coded the received (coded) message representative + * @param raw the computed (local, uncoded) message representative + * @param key_bits the size of the key in bits + * @return true if coded is a valid encoding of raw, otherwise false + */ + virtual bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) = 0; + virtual ~EMSA() {} + }; + +/** +* Factory method for EMSA (message-encoding methods for signatures +* with appendix) objects +* @param algo_spec the name of the EME to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL EMSA* get_emsa(const std::string& algo_spec); + +} + +#endif diff --git a/src/lib/pk_pad/emsa1/emsa1.cpp b/src/lib/pk_pad/emsa1/emsa1.cpp new file mode 100644 index 000000000..2358023f8 --- /dev/null +++ b/src/lib/pk_pad/emsa1/emsa1.cpp @@ -0,0 +1,105 @@ +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +secure_vector emsa1_encoding(const secure_vector& msg, + size_t output_bits) + { + if(8*msg.size() <= output_bits) + return msg; + + size_t shift = 8*msg.size() - output_bits; + + size_t byte_shift = shift / 8, bit_shift = shift % 8; + secure_vector digest(msg.size() - byte_shift); + + for(size_t j = 0; j != msg.size() - byte_shift; ++j) + digest[j] = msg[j]; + + if(bit_shift) + { + byte carry = 0; + for(size_t j = 0; j != digest.size(); ++j) + { + byte temp = digest[j]; + digest[j] = (temp >> bit_shift) | carry; + carry = (temp << (8 - bit_shift)); + } + } + return digest; + } + +} + +/* +* EMSA1 Update Operation +*/ +void EMSA1::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA1::raw_data() + { + return hash->final(); + } + +/* +* EMSA1 Encode Operation +*/ +secure_vector EMSA1::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash->output_length()) + throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); + return emsa1_encoding(msg, output_bits); + } + +/* +* EMSA1 Decode/Verify Operation +*/ +bool EMSA1::verify(const secure_vector& coded, + const secure_vector& raw, size_t key_bits) + { + try { + if(raw.size() != hash->output_length()) + throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); + + secure_vector our_coding = emsa1_encoding(raw, key_bits); + + if(our_coding == coded) return true; + if(our_coding.empty() || our_coding[0] != 0) return false; + if(our_coding.size() <= coded.size()) return false; + + size_t offset = 0; + while(offset < our_coding.size() && our_coding[offset] == 0) + ++offset; + if(our_coding.size() - offset != coded.size()) + return false; + + for(size_t j = 0; j != coded.size(); ++j) + if(coded[j] != our_coding[j+offset]) + return false; + + return true; + } + catch(Invalid_Argument) + { + return false; + } + } + +} diff --git a/src/lib/pk_pad/emsa1/emsa1.h b/src/lib/pk_pad/emsa1/emsa1.h new file mode 100644 index 000000000..f84ca5ae7 --- /dev/null +++ b/src/lib/pk_pad/emsa1/emsa1.h @@ -0,0 +1,48 @@ +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EMSA1_H__ +#define BOTAN_EMSA1_H__ + +#include +#include + +namespace Botan { + +/** +* EMSA1 from IEEE 1363 +* Essentially, sign the hash directly +*/ +class BOTAN_DLL EMSA1 : public EMSA + { + public: + /** + * @param h the hash object to use + */ + EMSA1(HashFunction* h) : hash(h) {} + ~EMSA1() { delete hash; } + protected: + /** + * @return const pointer to the underlying hash + */ + const HashFunction* hash_ptr() const { return hash; } + private: + void update(const byte[], size_t); + secure_vector raw_data(); + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng); + + bool verify(const secure_vector&, const secure_vector&, + size_t); + + HashFunction* hash; + }; + +} + +#endif diff --git a/src/lib/pk_pad/emsa1/info.txt b/src/lib/pk_pad/emsa1/info.txt new file mode 100644 index 000000000..83d9744e6 --- /dev/null +++ b/src/lib/pk_pad/emsa1/info.txt @@ -0,0 +1,5 @@ +define EMSA1 20131128 + + +hash + diff --git a/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp b/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp new file mode 100644 index 000000000..9096edfbf --- /dev/null +++ b/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp @@ -0,0 +1,29 @@ +/* +* EMSA1 BSI +* (C) 1999-2008 Jack Lloyd +* 2008 Falko Strenzke, FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* EMSA1 BSI Encode Operation +*/ +secure_vector EMSA1_BSI::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash_ptr()->output_length()) + throw Encoding_Error("EMSA1_BSI::encoding_of: Invalid size for input"); + + if(8*msg.size() <= output_bits) + return msg; + + throw Encoding_Error("EMSA1_BSI::encoding_of: max key input size exceeded"); + } + +} diff --git a/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h b/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h new file mode 100644 index 000000000..1b90f48df --- /dev/null +++ b/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h @@ -0,0 +1,35 @@ +/* +* EMSA1 BSI Variant +* (C) 1999-2008 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EMSA1_BSI_H__ +#define BOTAN_EMSA1_BSI_H__ + +#include + +namespace Botan { + +/** +EMSA1_BSI is a variant of EMSA1 specified by the BSI. It accepts only +hash values which are less or equal than the maximum key length. The +implementation comes from InSiTo +*/ +class BOTAN_DLL EMSA1_BSI : public EMSA1 + { + public: + /** + * @param hash the hash object to use + */ + EMSA1_BSI(HashFunction* hash) : EMSA1(hash) {} + private: + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng); + }; + +} + +#endif diff --git a/src/lib/pk_pad/emsa1_bsi/info.txt b/src/lib/pk_pad/emsa1_bsi/info.txt new file mode 100644 index 000000000..021c99720 --- /dev/null +++ b/src/lib/pk_pad/emsa1_bsi/info.txt @@ -0,0 +1,5 @@ +define EMSA1_BSI 20131128 + + +emsa1 + diff --git a/src/lib/pk_pad/emsa2/emsa2.cpp b/src/lib/pk_pad/emsa2/emsa2.cpp new file mode 100644 index 000000000..02a3dbe72 --- /dev/null +++ b/src/lib/pk_pad/emsa2/emsa2.cpp @@ -0,0 +1,112 @@ +/* +* EMSA2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* EMSA2 Encode Operation +*/ +secure_vector emsa2_encoding(const secure_vector& msg, + size_t output_bits, + const secure_vector& empty_hash, + byte hash_id) + { + const size_t HASH_SIZE = empty_hash.size(); + + size_t output_length = (output_bits + 1) / 8; + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("EMSA2::encoding_of: Bad input length"); + if(output_length < HASH_SIZE + 4) + throw Encoding_Error("EMSA2::encoding_of: Output length is too small"); + + bool empty = true; + for(size_t j = 0; j != HASH_SIZE; ++j) + if(empty_hash[j] != msg[j]) + empty = false; + + secure_vector output(output_length); + + output[0] = (empty ? 0x4B : 0x6B); + output[output_length - 3 - HASH_SIZE] = 0xBA; + set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB); + buffer_insert(output, output_length - (HASH_SIZE + 2), &msg[0], msg.size()); + output[output_length-2] = hash_id; + output[output_length-1] = 0xCC; + + return output; + } + +} + +/* +* EMSA2 Update Operation +*/ +void EMSA2::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA2::raw_data() + { + return hash->final(); + } + +/* +* EMSA2 Encode Operation +*/ +secure_vector EMSA2::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa2_encoding(msg, output_bits, empty_hash, hash_id); + } + +/* +* EMSA2 Verify Operation +*/ +bool EMSA2::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + try + { + return (coded == emsa2_encoding(raw, key_bits, + empty_hash, hash_id)); + } + catch(...) + { + return false; + } + } + +/* +* EMSA2 Constructor +*/ +EMSA2::EMSA2(HashFunction* hash_in) : hash(hash_in) + { + empty_hash = hash->final(); + + const std::string hash_name = hash->name(); + hash_id = ieee1363_hash_id(hash_name); + + if(hash_id == 0) + { + delete hash; + throw Encoding_Error("EMSA2 no hash identifier for " + hash_name); + } + } + +} diff --git a/src/lib/pk_pad/emsa2/emsa2.h b/src/lib/pk_pad/emsa2/emsa2.h new file mode 100644 index 000000000..fb0cecb21 --- /dev/null +++ b/src/lib/pk_pad/emsa2/emsa2.h @@ -0,0 +1,45 @@ +/* +* EMSA2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EMSA2_H__ +#define BOTAN_EMSA2_H__ + +#include +#include + +namespace Botan { + +/** +* EMSA2 from IEEE 1363 +* Useful for Rabin-Williams +*/ +class BOTAN_DLL EMSA2 : public EMSA + { + public: + /** + * @param hash the hash object to use + */ + EMSA2(HashFunction* hash); + ~EMSA2() { delete hash; } + private: + void update(const byte[], size_t); + secure_vector raw_data(); + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng); + + bool verify(const secure_vector&, const secure_vector&, + size_t); + + secure_vector empty_hash; + HashFunction* hash; + byte hash_id; + }; + +} + +#endif diff --git a/src/lib/pk_pad/emsa2/info.txt b/src/lib/pk_pad/emsa2/info.txt new file mode 100644 index 000000000..0c9bd2289 --- /dev/null +++ b/src/lib/pk_pad/emsa2/info.txt @@ -0,0 +1,6 @@ +define EMSA2 20131128 + + +hash +hash_id + diff --git a/src/lib/pk_pad/emsa3/emsa3.cpp b/src/lib/pk_pad/emsa3/emsa3.cpp new file mode 100644 index 000000000..0d603c508 --- /dev/null +++ b/src/lib/pk_pad/emsa3/emsa3.cpp @@ -0,0 +1,152 @@ +/* +* EMSA3 and EMSA3_Raw +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* EMSA3 Encode Operation +*/ +secure_vector emsa3_encoding(const secure_vector& msg, + size_t output_bits, + const byte hash_id[], + size_t hash_id_length) + { + size_t output_length = output_bits / 8; + if(output_length < hash_id_length + msg.size() + 10) + throw Encoding_Error("emsa3_encoding: Output length is too small"); + + secure_vector T(output_length); + const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2; + + T[0] = 0x01; + set_mem(&T[1], P_LENGTH, 0xFF); + T[P_LENGTH+1] = 0x00; + buffer_insert(T, P_LENGTH+2, hash_id, hash_id_length); + buffer_insert(T, output_length-msg.size(), &msg[0], msg.size()); + return T; + } + +} + +/* +* EMSA3 Update Operation +*/ +void EMSA3::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA3::raw_data() + { + return hash->final(); + } + +/* +* EMSA3 Encode Operation +*/ +secure_vector EMSA3::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash->output_length()) + throw Encoding_Error("EMSA3::encoding_of: Bad input length"); + + return emsa3_encoding(msg, output_bits, + &hash_id[0], hash_id.size()); + } + +/* +* Default signature decoding +*/ +bool EMSA3::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + if(raw.size() != hash->output_length()) + return false; + + try + { + return (coded == emsa3_encoding(raw, key_bits, + &hash_id[0], hash_id.size())); + } + catch(...) + { + return false; + } + } + +/* +* EMSA3 Constructor +*/ +EMSA3::EMSA3(HashFunction* hash_in) : hash(hash_in) + { + hash_id = pkcs_hash_id(hash->name()); + } + +/* +* EMSA3 Destructor +*/ +EMSA3::~EMSA3() + { + delete hash; + } + +/* +* EMSA3_Raw Update Operation +*/ +void EMSA3_Raw::update(const byte input[], size_t length) + { + message += std::make_pair(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA3_Raw::raw_data() + { + secure_vector ret; + std::swap(ret, message); + return ret; + } + +/* +* EMSA3_Raw Encode Operation +*/ +secure_vector EMSA3_Raw::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa3_encoding(msg, output_bits, nullptr, 0); + } + +/* +* Default signature decoding +*/ +bool EMSA3_Raw::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + try + { + return (coded == emsa3_encoding(raw, key_bits, nullptr, 0)); + } + catch(...) + { + return false; + } + } + +} diff --git a/src/lib/pk_pad/emsa3/emsa3.h b/src/lib/pk_pad/emsa3/emsa3.h new file mode 100644 index 000000000..9fbda67ee --- /dev/null +++ b/src/lib/pk_pad/emsa3/emsa3.h @@ -0,0 +1,68 @@ +/* +* EMSA3 and EMSA3_Raw +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EMSA3_H__ +#define BOTAN_EMSA3_H__ + +#include +#include + +namespace Botan { + +/** +* EMSA3 from IEEE 1363 +* aka PKCS #1 v1.5 signature padding +* aka PKCS #1 block type 1 +*/ +class BOTAN_DLL EMSA3 : public EMSA + { + public: + /** + * @param hash the hash object to use + */ + EMSA3(HashFunction* hash); + ~EMSA3(); + + void update(const byte[], size_t); + + secure_vector raw_data(); + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng); + + bool verify(const secure_vector&, const secure_vector&, + size_t); + private: + HashFunction* hash; + std::vector hash_id; + }; + +/** +* EMSA3_Raw which is EMSA3 without a hash or digest id (which +* according to QCA docs is "identical to PKCS#11's CKM_RSA_PKCS +* mechanism", something I have not confirmed) +*/ +class BOTAN_DLL EMSA3_Raw : public EMSA + { + public: + void update(const byte[], size_t); + + secure_vector raw_data(); + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng); + + bool verify(const secure_vector&, const secure_vector&, + size_t); + + private: + secure_vector message; + }; + +} + +#endif diff --git a/src/lib/pk_pad/emsa3/info.txt b/src/lib/pk_pad/emsa3/info.txt new file mode 100644 index 000000000..aea998f13 --- /dev/null +++ b/src/lib/pk_pad/emsa3/info.txt @@ -0,0 +1,6 @@ +define EMSA3 20131128 + + +hash +hash_id + diff --git a/src/lib/pk_pad/emsa4/emsa4.cpp b/src/lib/pk_pad/emsa4/emsa4.cpp new file mode 100644 index 000000000..c8b8cbc6a --- /dev/null +++ b/src/lib/pk_pad/emsa4/emsa4.cpp @@ -0,0 +1,146 @@ +/* +* EMSA4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* EMSA4 Update Operation +*/ +void EMSA4::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA4::raw_data() + { + return hash->final(); + } + +/* +* EMSA4 Encode Operation +*/ +secure_vector EMSA4::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + const size_t HASH_SIZE = hash->output_length(); + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("EMSA4::encoding_of: Bad input length"); + if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9) + throw Encoding_Error("EMSA4::encoding_of: Output length is too small"); + + const size_t output_length = (output_bits + 7) / 8; + + secure_vector salt = rng.random_vec(SALT_SIZE); + + for(size_t j = 0; j != 8; ++j) + hash->update(0); + hash->update(msg); + hash->update(salt); + secure_vector H = hash->final(); + + secure_vector EM(output_length); + + EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01; + buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt); + mgf->mask(&H[0], HASH_SIZE, &EM[0], output_length - HASH_SIZE - 1); + EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); + buffer_insert(EM, output_length - 1 - HASH_SIZE, H); + EM[output_length-1] = 0xBC; + + return EM; + } + +/* +* EMSA4 Decode/Verify Operation +*/ +bool EMSA4::verify(const secure_vector& const_coded, + const secure_vector& raw, size_t key_bits) + { + const size_t HASH_SIZE = hash->output_length(); + const size_t KEY_BYTES = (key_bits + 7) / 8; + + if(key_bits < 8*HASH_SIZE + 9) + return false; + + if(raw.size() != HASH_SIZE) + return false; + + if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1) + return false; + + if(const_coded[const_coded.size()-1] != 0xBC) + return false; + + secure_vector coded = const_coded; + if(coded.size() < KEY_BYTES) + { + secure_vector temp(KEY_BYTES); + buffer_insert(temp, KEY_BYTES - coded.size(), coded); + coded = temp; + } + + const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; + if(TOP_BITS > 8 - high_bit(coded[0])) + return false; + + byte* DB = &coded[0]; + const size_t DB_size = coded.size() - HASH_SIZE - 1; + + const byte* H = &coded[DB_size]; + const size_t H_size = HASH_SIZE; + + mgf->mask(&H[0], H_size, &DB[0], DB_size); + DB[0] &= 0xFF >> TOP_BITS; + + size_t salt_offset = 0; + for(size_t j = 0; j != DB_size; ++j) + { + if(DB[j] == 0x01) + { salt_offset = j + 1; break; } + if(DB[j]) + return false; + } + if(salt_offset == 0) + return false; + + for(size_t j = 0; j != 8; ++j) + hash->update(0); + hash->update(raw); + hash->update(&DB[salt_offset], DB_size - salt_offset); + secure_vector H2 = hash->final(); + + return same_mem(&H[0], &H2[0], HASH_SIZE); + } + +/* +* EMSA4 Constructor +*/ +EMSA4::EMSA4(HashFunction* h) : + SALT_SIZE(h->output_length()), hash(h) + { + mgf = new MGF1(hash->clone()); + } + +/* +* EMSA4 Constructor +*/ +EMSA4::EMSA4(HashFunction* h, size_t salt_size) : + SALT_SIZE(salt_size), hash(h) + { + mgf = new MGF1(hash->clone()); + } + +} diff --git a/src/lib/pk_pad/emsa4/emsa4.h b/src/lib/pk_pad/emsa4/emsa4.h new file mode 100644 index 000000000..44bf5a429 --- /dev/null +++ b/src/lib/pk_pad/emsa4/emsa4.h @@ -0,0 +1,51 @@ +/* +* EMSA4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EMSA4_H__ +#define BOTAN_EMSA4_H__ + +#include +#include +#include + +namespace Botan { + +/** +* EMSA4 aka PSS-R +*/ +class BOTAN_DLL EMSA4 : public EMSA + { + public: + /** + * @param hash the hash object to use + */ + EMSA4(HashFunction* hash); + + /** + * @param hash the hash object to use + * @param salt_size the size of the salt to use in bytes + */ + EMSA4(HashFunction* hash, size_t salt_size); + + ~EMSA4() { delete hash; delete mgf; } + private: + void update(const byte[], size_t); + secure_vector raw_data(); + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng); + bool verify(const secure_vector&, const secure_vector&, + size_t); + + size_t SALT_SIZE; + HashFunction* hash; + const MGF* mgf; + }; + +} + +#endif diff --git a/src/lib/pk_pad/emsa4/info.txt b/src/lib/pk_pad/emsa4/info.txt new file mode 100644 index 000000000..b7ea466ce --- /dev/null +++ b/src/lib/pk_pad/emsa4/info.txt @@ -0,0 +1,7 @@ +define EMSA4 20131128 + + +hash +kdf +mgf1 + diff --git a/src/lib/pk_pad/emsa_raw/emsa_raw.cpp b/src/lib/pk_pad/emsa_raw/emsa_raw.cpp new file mode 100644 index 000000000..cb0f99e9c --- /dev/null +++ b/src/lib/pk_pad/emsa_raw/emsa_raw.cpp @@ -0,0 +1,68 @@ +/* +* EMSA-Raw +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* EMSA-Raw Encode Operation +*/ +void EMSA_Raw::update(const byte input[], size_t length) + { + message += std::make_pair(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA_Raw::raw_data() + { + secure_vector output; + std::swap(message, output); + return output; + } + +/* +* EMSA-Raw Encode Operation +*/ +secure_vector EMSA_Raw::encoding_of(const secure_vector& msg, + size_t, + RandomNumberGenerator&) + { + return msg; + } + +/* +* EMSA-Raw Verify Operation +*/ +bool EMSA_Raw::verify(const secure_vector& coded, + const secure_vector& raw, + size_t) + { + if(coded.size() == raw.size()) + return (coded == raw); + + if(coded.size() > raw.size()) + return false; + + // handle zero padding differences + const size_t leading_zeros_expected = raw.size() - coded.size(); + + bool same_modulo_leading_zeros = true; + + for(size_t i = 0; i != leading_zeros_expected; ++i) + if(raw[i]) + same_modulo_leading_zeros = false; + + if(!same_mem(&coded[0], &raw[leading_zeros_expected], coded.size())) + same_modulo_leading_zeros = false; + + return same_modulo_leading_zeros; + } + +} diff --git a/src/lib/pk_pad/emsa_raw/emsa_raw.h b/src/lib/pk_pad/emsa_raw/emsa_raw.h new file mode 100644 index 000000000..8ab763575 --- /dev/null +++ b/src/lib/pk_pad/emsa_raw/emsa_raw.h @@ -0,0 +1,35 @@ +/* +* EMSA-Raw +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EMSA_RAW_H__ +#define BOTAN_EMSA_RAW_H__ + +#include + +namespace Botan { + +/** +* EMSA-Raw - sign inputs directly +* Don't use this unless you know what you are doing. +*/ +class BOTAN_DLL EMSA_Raw : public EMSA + { + private: + void update(const byte[], size_t); + secure_vector raw_data(); + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator&); + bool verify(const secure_vector&, const secure_vector&, + size_t); + + secure_vector message; + }; + +} + +#endif diff --git a/src/lib/pk_pad/emsa_raw/info.txt b/src/lib/pk_pad/emsa_raw/info.txt new file mode 100644 index 000000000..f01d1bfa2 --- /dev/null +++ b/src/lib/pk_pad/emsa_raw/info.txt @@ -0,0 +1 @@ +define EMSA_RAW 20131128 diff --git a/src/lib/pk_pad/get_pk_pad.cpp b/src/lib/pk_pad/get_pk_pad.cpp new file mode 100644 index 000000000..8c27b1fa1 --- /dev/null +++ b/src/lib/pk_pad/get_pk_pad.cpp @@ -0,0 +1,139 @@ +/* +* EMSA/EME Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_EMSA1) + #include +#endif + +#if defined(BOTAN_HAS_EMSA1_BSI) + #include +#endif + +#if defined(BOTAN_HAS_EMSA2) + #include +#endif + +#if defined(BOTAN_HAS_EMSA3) + #include +#endif + +#if defined(BOTAN_HAS_EMSA4) + #include +#endif + +#if defined(BOTAN_HAS_EMSA_RAW) + #include +#endif + +#if defined(BOTAN_HAS_EME1) + #include +#endif + +#if defined(BOTAN_HAS_EME_PKCS1v15) + #include +#endif + +namespace Botan { + +/* +* Get an EMSA by name +*/ +EMSA* get_emsa(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + Algorithm_Factory& af = global_state().algorithm_factory(); + +#if defined(BOTAN_HAS_EMSA_RAW) + if(request.algo_name() == "Raw" && request.arg_count() == 0) + return new EMSA_Raw; +#endif + +#if defined(BOTAN_HAS_EMSA1) + if(request.algo_name() == "EMSA1" && request.arg_count() == 1) + { + if(request.arg(0) == "Raw") + return new EMSA_Raw; + return new EMSA1(af.make_hash_function(request.arg(0))); + } +#endif + +#if defined(BOTAN_HAS_EMSA1_BSI) + if(request.algo_name() == "EMSA1_BSI" && request.arg_count() == 1) + return new EMSA1_BSI(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_EMSA2) + if(request.algo_name() == "EMSA2" && request.arg_count() == 1) + return new EMSA2(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_EMSA3) + if(request.algo_name() == "EMSA3" && request.arg_count() == 1) + { + if(request.arg(0) == "Raw") + return new EMSA3_Raw; + return new EMSA3(af.make_hash_function(request.arg(0))); + } +#endif + +#if defined(BOTAN_HAS_EMSA4) + if(request.algo_name() == "EMSA4" && request.arg_count_between(1, 3)) + { + // 3 args: Hash, MGF, salt size (MGF is hardcoded MGF1 in Botan) + if(request.arg_count() == 1) + return new EMSA4(af.make_hash_function(request.arg(0))); + + if(request.arg_count() == 2 && request.arg(1) != "MGF1") + return new EMSA4(af.make_hash_function(request.arg(0))); + + if(request.arg_count() == 3) + return new EMSA4(af.make_hash_function(request.arg(0)), + request.arg_as_integer(2, 0)); + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get an EME by name +*/ +EME* get_eme(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(request.algo_name() == "Raw") + return nullptr; // No padding + +#if defined(BOTAN_HAS_EME_PKCS1v15) + if(request.algo_name() == "PKCS1v15" && request.arg_count() == 0) + return new EME_PKCS1v15; +#endif + +#if defined(BOTAN_HAS_EME1) + if(request.algo_name() == "EME1" && request.arg_count_between(1, 2)) + { + if(request.arg_count() == 1 || + (request.arg_count() == 2 && request.arg(1) == "MGF1")) + { + return new EME1(af.make_hash_function(request.arg(0))); + } + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +} diff --git a/src/lib/pk_pad/hash_id/hash_id.cpp b/src/lib/pk_pad/hash_id/hash_id.cpp new file mode 100644 index 000000000..a60e53352 --- /dev/null +++ b/src/lib/pk_pad/hash_id/hash_id.cpp @@ -0,0 +1,129 @@ +/* +* Hash Function Identification +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +const byte MD2_PKCS_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 }; + +const byte MD5_PKCS_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + +const byte RIPEMD_128_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x02, 0x05, 0x00, 0x04, 0x14 }; + +const byte RIPEMD_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x01, 0x05, 0x00, 0x04, 0x14 }; + +const byte SHA_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, +0x1A, 0x05, 0x00, 0x04, 0x14 }; + +const byte SHA_224_PKCS_ID[] = { +0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C }; + +const byte SHA_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; + +const byte SHA_384_PKCS_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; + +const byte SHA_512_PKCS_ID[] = { +0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; + +const byte TIGER_PKCS_ID[] = { +0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, +0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 }; + +} + +/* +* HashID as specified by PKCS +*/ +std::vector pkcs_hash_id(const std::string& name) + { + // Special case for SSL/TLS RSA signatures + if(name == "Parallel(MD5,SHA-160)") + return std::vector(); + + if(name == "MD2") + return std::vector(MD2_PKCS_ID, + MD2_PKCS_ID + sizeof(MD2_PKCS_ID)); + + if(name == "MD5") + return std::vector(MD5_PKCS_ID, + MD5_PKCS_ID + sizeof(MD5_PKCS_ID)); + + if(name == "RIPEMD-128") + return std::vector(RIPEMD_128_PKCS_ID, + RIPEMD_128_PKCS_ID + sizeof(RIPEMD_128_PKCS_ID)); + + if(name == "RIPEMD-160") + return std::vector(RIPEMD_160_PKCS_ID, + RIPEMD_160_PKCS_ID + sizeof(RIPEMD_160_PKCS_ID)); + + if(name == "SHA-160") + return std::vector(SHA_160_PKCS_ID, + SHA_160_PKCS_ID + sizeof(SHA_160_PKCS_ID)); + + if(name == "SHA-224") + return std::vector(SHA_224_PKCS_ID, + SHA_224_PKCS_ID + sizeof(SHA_224_PKCS_ID)); + + if(name == "SHA-256") + return std::vector(SHA_256_PKCS_ID, + SHA_256_PKCS_ID + sizeof(SHA_256_PKCS_ID)); + + if(name == "SHA-384") + return std::vector(SHA_384_PKCS_ID, + SHA_384_PKCS_ID + sizeof(SHA_384_PKCS_ID)); + + if(name == "SHA-512") + return std::vector(SHA_512_PKCS_ID, + SHA_512_PKCS_ID + sizeof(SHA_512_PKCS_ID)); + + if(name == "Tiger(24,3)") + return std::vector(TIGER_PKCS_ID, + TIGER_PKCS_ID + sizeof(TIGER_PKCS_ID)); + + throw Invalid_Argument("No PKCS #1 identifier for " + name); + } + +/* +* HashID as specified by IEEE 1363/X9.31 +*/ +byte ieee1363_hash_id(const std::string& name) + { + if(name == "SHA-160") return 0x33; + + if(name == "SHA-224") return 0x38; + if(name == "SHA-256") return 0x34; + if(name == "SHA-384") return 0x36; + if(name == "SHA-512") return 0x35; + + if(name == "RIPEMD-160") return 0x31; + if(name == "RIPEMD-128") return 0x32; + + if(name == "Whirlpool") return 0x37; + + return 0; + } + +} diff --git a/src/lib/pk_pad/hash_id/hash_id.h b/src/lib/pk_pad/hash_id/hash_id.h new file mode 100644 index 000000000..070e7ddb9 --- /dev/null +++ b/src/lib/pk_pad/hash_id/hash_id.h @@ -0,0 +1,34 @@ +/* +* Hash Function Identification +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HASHID_H__ +#define BOTAN_HASHID_H__ + +#include +#include + +namespace Botan { + +/** +* Return the PKCS #1 hash identifier +* @see RFC 3447 section 9.2 +* @param hash_name the name of the hash function +* @return byte sequence identifying the hash +* @throw Invalid_Argument if the hash has no known PKCS #1 hash id +*/ +BOTAN_DLL std::vector pkcs_hash_id(const std::string& hash_name); + +/** +* Return the IEEE 1363 hash identifier +* @param hash_name the name of the hash function +* @return byte code identifying the hash, or 0 if not known +*/ +BOTAN_DLL byte ieee1363_hash_id(const std::string& hash_name); + +} + +#endif diff --git a/src/lib/pk_pad/hash_id/info.txt b/src/lib/pk_pad/hash_id/info.txt new file mode 100644 index 000000000..e6df99b6f --- /dev/null +++ b/src/lib/pk_pad/hash_id/info.txt @@ -0,0 +1,5 @@ +define HASH_ID 20131128 + + +alloc + diff --git a/src/lib/pk_pad/info.txt b/src/lib/pk_pad/info.txt new file mode 100644 index 000000000..5c6a9e4a7 --- /dev/null +++ b/src/lib/pk_pad/info.txt @@ -0,0 +1,8 @@ +define PK_PADDING 20131128 + +load_on auto + + +alloc +rng + diff --git a/src/lib/prf/hkdf/hkdf.cpp b/src/lib/prf/hkdf/hkdf.cpp new file mode 100644 index 000000000..0a1f7cb31 --- /dev/null +++ b/src/lib/prf/hkdf/hkdf.cpp @@ -0,0 +1,62 @@ +/* +* HKDF +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +std::string HKDF::name() const + { + return "HKDF(" + m_prf->name() + ")"; + } + +void HKDF::clear() + { + m_extractor->clear(); + m_prf->clear(); + } + +void HKDF::start_extract(const byte salt[], size_t salt_len) + { + m_extractor->set_key(salt, salt_len); + } + +void HKDF::extract(const byte input[], size_t input_len) + { + m_extractor->update(input, input_len); + } + +void HKDF::finish_extract() + { + m_prf->set_key(m_extractor->final()); + } + +void HKDF::expand(byte output[], size_t output_len, + const byte info[], size_t info_len) + { + if(output_len > m_prf->output_length() * 255) + throw std::invalid_argument("HKDF requested output too large"); + + byte counter = 1; + + secure_vector T; + + while(output_len) + { + m_prf->update(T); + m_prf->update(info, info_len); + m_prf->update(counter++); + T = m_prf->final(); + + const size_t to_write = std::min(T.size(), output_len); + copy_mem(&output[0], &T[0], to_write); + output += to_write; + output_len -= to_write; + } + } + +} diff --git a/src/lib/prf/hkdf/hkdf.h b/src/lib/prf/hkdf/hkdf.h new file mode 100644 index 000000000..e0b5a7376 --- /dev/null +++ b/src/lib/prf/hkdf/hkdf.h @@ -0,0 +1,51 @@ +/* +* HKDF +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HKDF_H__ +#define BOTAN_HKDF_H__ + +#include +#include +#include + +namespace Botan { + +/** +* HKDF, see @rfc 5869 for details +*/ +class BOTAN_DLL HKDF + { + public: + HKDF(MessageAuthenticationCode* extractor, + MessageAuthenticationCode* prf) : + m_extractor(extractor), m_prf(prf) {} + + HKDF(MessageAuthenticationCode* prf) : + m_extractor(prf), m_prf(m_extractor->clone()) {} + + void start_extract(const byte salt[], size_t salt_len); + void extract(const byte input[], size_t input_len); + void finish_extract(); + + /** + * Only call after extract + * @param output_len must be less than 256*hashlen + */ + void expand(byte output[], size_t output_len, + const byte info[], size_t info_len); + + std::string name() const; + + void clear(); + private: + std::unique_ptr m_extractor; + std::unique_ptr m_prf; + }; + +} + +#endif diff --git a/src/lib/prf/hkdf/info.txt b/src/lib/prf/hkdf/info.txt new file mode 100644 index 000000000..7389e5bb1 --- /dev/null +++ b/src/lib/prf/hkdf/info.txt @@ -0,0 +1 @@ +define HKDF 20131128 diff --git a/src/lib/pubkey/blinding.cpp b/src/lib/pubkey/blinding.cpp new file mode 100644 index 000000000..c4c0e3b6e --- /dev/null +++ b/src/lib/pubkey/blinding.cpp @@ -0,0 +1,49 @@ +/* +* Blinding for public key operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Blinder Constructor +*/ +Blinder::Blinder(const BigInt& e, const BigInt& d, const BigInt& n) + { + if(e < 1 || d < 1 || n < 1) + throw Invalid_Argument("Blinder: Arguments too small"); + + reducer = Modular_Reducer(n); + this->e = e; + this->d = d; + } + +/* +* Blind a number +*/ +BigInt Blinder::blind(const BigInt& i) const + { + if(!reducer.initialized()) + return i; + + e = reducer.square(e); + d = reducer.square(d); + return reducer.multiply(i, e); + } + +/* +* Unblind a number +*/ +BigInt Blinder::unblind(const BigInt& i) const + { + if(!reducer.initialized()) + return i; + return reducer.multiply(i, d); + } + +} diff --git a/src/lib/pubkey/blinding.h b/src/lib/pubkey/blinding.h new file mode 100644 index 000000000..712030e4d --- /dev/null +++ b/src/lib/pubkey/blinding.h @@ -0,0 +1,46 @@ +/* +* Blinding for public key operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BLINDER_H__ +#define BOTAN_BLINDER_H__ + +#include +#include + +namespace Botan { + +/** +* Blinding Function Object +*/ +class BOTAN_DLL Blinder + { + public: + BigInt blind(const BigInt& x) const; + BigInt unblind(const BigInt& x) const; + + bool initialized() const { return reducer.initialized(); } + + Blinder() {} + + /** + * Construct a blinder + * @param mask the forward (blinding) mask + * @param inverse_mask the inverse of mask (depends on algo) + * @param modulus of the group operations are performed in + */ + Blinder(const BigInt& mask, + const BigInt& inverse_mask, + const BigInt& modulus); + + private: + Modular_Reducer reducer; + mutable BigInt e, d; + }; + +} + +#endif diff --git a/src/lib/pubkey/dh/dh.cpp b/src/lib/pubkey/dh/dh.cpp new file mode 100644 index 000000000..55d53518a --- /dev/null +++ b/src/lib/pubkey/dh/dh.cpp @@ -0,0 +1,98 @@ +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* DH_PublicKey Constructor +*/ +DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* Return the public value for key agreement +*/ +std::vector DH_PublicKey::public_value() const + { + return unlock(BigInt::encode_1363(y, group_p().bytes())); + } + +/* +* Create a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + { + const BigInt& p = group_p(); + x.randomize(rng, 2 * dl_work_factor(p.bits())); + } + + if(y == 0) + y = power_mod(group_g(), x, group_p()); + + if(x == 0) + gen_check(rng); + else + load_check(rng); + } + +/* +* Load a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + if(y == 0) + y = power_mod(group_g(), x, group_p()); + + load_check(rng); + } + +/* +* Return the public value for key agreement +*/ +std::vector DH_PrivateKey::public_value() const + { + return DH_PublicKey::public_value(); + } + +DH_KA_Operation::DH_KA_Operation(const DH_PrivateKey& dh, + RandomNumberGenerator& rng) : + p(dh.group_p()), powermod_x_p(dh.get_x(), p) + { + BigInt k(rng, p.bits() - 1); + blinder = Blinder(k, powermod_x_p(inverse_mod(k, p)), p); + } + +secure_vector DH_KA_Operation::agree(const byte w[], size_t w_len) + { + BigInt input = BigInt::decode(w, w_len); + + if(input <= 1 || input >= p - 1) + throw Invalid_Argument("DH agreement - invalid key provided"); + + BigInt r = blinder.unblind(powermod_x_p(blinder.blind(input))); + + return BigInt::encode_1363(r, p.bytes()); + } + +} diff --git a/src/lib/pubkey/dh/dh.h b/src/lib/pubkey/dh/dh.h new file mode 100644 index 000000000..c670399d8 --- /dev/null +++ b/src/lib/pubkey/dh/dh.h @@ -0,0 +1,94 @@ +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DIFFIE_HELLMAN_H__ +#define BOTAN_DIFFIE_HELLMAN_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents Diffie-Hellman public keys. +*/ +class BOTAN_DLL DH_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "DH"; } + + std::vector public_value() const; + size_t max_input_bits() const { return group_p().bits(); } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + + DH_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) {} + + /** + * Construct a public key with the specified parameters. + * @param grp the DL group to use in the key + * @param y the public value y + */ + DH_PublicKey(const DL_Group& grp, const BigInt& y); + protected: + DH_PublicKey() {} + }; + +/** +* This class represents Diffie-Hellman private keys. +*/ +class BOTAN_DLL DH_PrivateKey : public DH_PublicKey, + public PK_Key_Agreement_Key, + public virtual DL_Scheme_PrivateKey + { + public: + std::vector public_value() const; + + /** + * Load a DH private key + * @param alg_id the algorithm id + * @param key_bits the subject public key + * @param rng a random number generator + */ + DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng); + + /** + * Construct a private key with predetermined value. + * @param rng random number generator to use + * @param grp the group to be used in the key + * @param x the key's secret value (or if zero, generate a new key) + */ + DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, + const BigInt& x = 0); + }; + +/** +* DH operation +*/ +class BOTAN_DLL DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + DH_KA_Operation(const DH_PrivateKey& key, + RandomNumberGenerator& rng); + + secure_vector agree(const byte w[], size_t w_len); + private: + const BigInt& p; + + Fixed_Exponent_Power_Mod powermod_x_p; + Blinder blinder; + }; + +} + +#endif diff --git a/src/lib/pubkey/dh/info.txt b/src/lib/pubkey/dh/info.txt new file mode 100644 index 000000000..bb2707951 --- /dev/null +++ b/src/lib/pubkey/dh/info.txt @@ -0,0 +1,16 @@ +define DIFFIE_HELLMAN 20131128 + + +dh.h + + + +dh.cpp + + + +dl_algo +dl_group +libstate +numbertheory + diff --git a/src/lib/pubkey/dl_algo/dl_algo.cpp b/src/lib/pubkey/dl_algo/dl_algo.cpp new file mode 100644 index 000000000..92c78ac79 --- /dev/null +++ b/src/lib/pubkey/dl_algo/dl_algo.cpp @@ -0,0 +1,91 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +size_t DL_Scheme_PublicKey::estimated_strength() const + { + return dl_work_factor(group.get_p().bits()); + } + +AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + group.DER_encode(group_format())); + } + +std::vector DL_Scheme_PublicKey::x509_subject_public_key() const + { + return DER_Encoder().encode(y).get_contents_unlocked(); + } + +DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + DL_Group::Format format) + { + group.BER_decode(alg_id.parameters, format); + + BER_Decoder(key_bits).decode(y); + } + +secure_vector DL_Scheme_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder().encode(x).get_contents(); + } + +DL_Scheme_PrivateKey::DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + DL_Group::Format format) + { + group.BER_decode(alg_id.parameters, format); + + BER_Decoder(key_bits).decode(x); + } + +/* +* Check Public DL Parameters +*/ +bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(y < 2 || y >= group_p()) + return false; + if(!group.verify_group(rng, strong)) + return false; + return true; + } + +/* +* Check DL Scheme Private Parameters +*/ +bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + const BigInt& p = group_p(); + const BigInt& g = group_g(); + + if(y < 2 || y >= p || x < 2 || x >= p) + return false; + if(!group.verify_group(rng, strong)) + return false; + + if(!strong) + return true; + + if(y != power_mod(g, x, p)) + return false; + + return true; + } + +} diff --git a/src/lib/pubkey/dl_algo/dl_algo.h b/src/lib/pubkey/dl_algo/dl_algo.h new file mode 100644 index 000000000..abd2acba4 --- /dev/null +++ b/src/lib/pubkey/dl_algo/dl_algo.h @@ -0,0 +1,116 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DL_ALGO_H__ +#define BOTAN_DL_ALGO_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents discrete logarithm (DL) public keys. +*/ +class BOTAN_DLL DL_Scheme_PublicKey : public virtual Public_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + AlgorithmIdentifier algorithm_identifier() const; + + std::vector x509_subject_public_key() const; + + /** + * Get the DL domain parameters of this key. + * @return DL domain parameters of this key + */ + const DL_Group& get_domain() const { return group; } + + /** + * Get the public value y with y = g^x mod p where x is the secret key. + */ + const BigInt& get_y() const { return y; } + + /** + * Get the prime p of the underlying DL group. + * @return prime p + */ + const BigInt& group_p() const { return group.get_p(); } + + /** + * Get the prime q of the underlying DL group. + * @return prime q + */ + const BigInt& group_q() const { return group.get_q(); } + + /** + * Get the generator g of the underlying DL group. + * @return generator g + */ + const BigInt& group_g() const { return group.get_g(); } + + /** + * Get the underlying groups encoding format. + * @return encoding format + */ + virtual DL_Group::Format group_format() const = 0; + + size_t estimated_strength() const override; + + DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + DL_Group::Format group_format); + + protected: + DL_Scheme_PublicKey() {} + + /** + * The DL public key + */ + BigInt y; + + /** + * The DL group + */ + DL_Group group; + }; + +/** +* This class represents discrete logarithm (DL) private keys. +*/ +class BOTAN_DLL DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, + public virtual Private_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the secret key x. + * @return secret key + */ + const BigInt& get_x() const { return x; } + + secure_vector pkcs8_private_key() const; + + DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + DL_Group::Format group_format); + + protected: + DL_Scheme_PrivateKey() {} + + /** + * The DL private key + */ + BigInt x; + }; + +} + +#endif diff --git a/src/lib/pubkey/dl_algo/info.txt b/src/lib/pubkey/dl_algo/info.txt new file mode 100644 index 000000000..6f3b3195d --- /dev/null +++ b/src/lib/pubkey/dl_algo/info.txt @@ -0,0 +1,8 @@ +define DL_PUBLIC_KEY_FAMILY 20131128 + + +asn1 +dl_group +numbertheory +rng + diff --git a/src/lib/pubkey/dl_group/dl_group.cpp b/src/lib/pubkey/dl_group/dl_group.cpp new file mode 100644 index 000000000..6fd1beeaa --- /dev/null +++ b/src/lib/pubkey/dl_group/dl_group.cpp @@ -0,0 +1,337 @@ +/* +* Discrete Logarithm Parameters +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group() + { + initialized = false; + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const std::string& name) + { + const char* pem = PEM_for_named_group(name); + + if(!pem) + throw Invalid_Argument("DL_Group: Unknown group " + name); + + PEM_decode(pem); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + PrimeType type, size_t pbits, size_t qbits) + { + if(pbits < 512) + throw Invalid_Argument("DL_Group: prime size " + std::to_string(pbits) + + " is too small"); + + if(type == Strong) + { + p = random_safe_prime(rng, pbits); + q = (p - 1) / 2; + g = 2; + } + else if(type == Prime_Subgroup) + { + if(!qbits) + qbits = 2 * dl_work_factor(pbits); + + q = random_prime(rng, qbits); + BigInt X; + while(p.bits() != pbits || !check_prime(p, rng)) + { + X.randomize(rng, pbits); + p = X - (X % (2*q) - 1); + } + + g = make_dsa_generator(p, q); + } + else if(type == DSA_Kosherizer) + { + qbits = qbits ? qbits : ((pbits <= 1024) ? 160 : 256); + + generate_dsa_primes(rng, + global_state().algorithm_factory(), + p, q, + pbits, qbits); + + g = make_dsa_generator(p, q); + } + + initialized = true; + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + const std::vector& seed, + size_t pbits, size_t qbits) + { + if(!generate_dsa_primes(rng, + global_state().algorithm_factory(), + p, q, pbits, qbits, seed)) + throw Invalid_Argument("DL_Group: The seed given does not " + "generate a DSA group"); + + g = make_dsa_generator(p, q); + + initialized = true; + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p1, const BigInt& g1) + { + initialize(p1, 0, g1); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p1, const BigInt& q1, const BigInt& g1) + { + initialize(p1, q1, g1); + } + +/* +* DL_Group Initializer +*/ +void DL_Group::initialize(const BigInt& p1, const BigInt& q1, const BigInt& g1) + { + if(p1 < 3) + throw Invalid_Argument("DL_Group: Prime invalid"); + if(g1 < 2 || g1 >= p1) + throw Invalid_Argument("DL_Group: Generator invalid"); + if(q1 < 0 || q1 >= p1) + throw Invalid_Argument("DL_Group: Subgroup invalid"); + + p = p1; + g = g1; + q = q1; + + initialized = true; + } + +/* +* Verify that the group has been set +*/ +void DL_Group::init_check() const + { + if(!initialized) + throw Invalid_State("DLP group cannot be used uninitialized"); + } + +/* +* Verify the parameters +*/ +bool DL_Group::verify_group(RandomNumberGenerator& rng, + bool strong) const + { + init_check(); + + if(g < 2 || p < 3 || q < 0) + return false; + if((q != 0) && ((p - 1) % q != 0)) + return false; + + if(!strong) + return true; + + if(!check_prime(p, rng)) + return false; + if((q > 0) && !check_prime(q, rng)) + return false; + return true; + } + +/* +* Return the prime +*/ +const BigInt& DL_Group::get_p() const + { + init_check(); + return p; + } + +/* +* Return the generator +*/ +const BigInt& DL_Group::get_g() const + { + init_check(); + return g; + } + +/* +* Return the subgroup +*/ +const BigInt& DL_Group::get_q() const + { + init_check(); + if(q == 0) + throw Invalid_State("DLP group has no q prime specified"); + return q; + } + +/* +* DER encode the parameters +*/ +std::vector DL_Group::DER_encode(Format format) const + { + init_check(); + + if((q == 0) && (format != PKCS_3)) + throw Encoding_Error("The ANSI DL parameter formats require a subgroup"); + + if(format == ANSI_X9_57) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(q) + .encode(g) + .end_cons() + .get_contents_unlocked(); + } + else if(format == ANSI_X9_42) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(g) + .encode(q) + .end_cons() + .get_contents_unlocked(); + } + else if(format == PKCS_3) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(g) + .end_cons() + .get_contents_unlocked(); + } + + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + } + +/* +* PEM encode the parameters +*/ +std::string DL_Group::PEM_encode(Format format) const + { + const std::vector encoding = DER_encode(format); + + if(format == PKCS_3) + return PEM_Code::encode(encoding, "DH PARAMETERS"); + else if(format == ANSI_X9_57) + return PEM_Code::encode(encoding, "DSA PARAMETERS"); + else if(format == ANSI_X9_42) + return PEM_Code::encode(encoding, "X942 DH PARAMETERS"); + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + } + +/* +* Decode BER encoded parameters +*/ +void DL_Group::BER_decode(const std::vector& data, + Format format) + { + BigInt new_p, new_q, new_g; + + BER_Decoder decoder(data); + BER_Decoder ber = decoder.start_cons(SEQUENCE); + + if(format == ANSI_X9_57) + { + ber.decode(new_p) + .decode(new_q) + .decode(new_g) + .verify_end(); + } + else if(format == ANSI_X9_42) + { + ber.decode(new_p) + .decode(new_g) + .decode(new_q) + .discard_remaining(); + } + else if(format == PKCS_3) + { + ber.decode(new_p) + .decode(new_g) + .discard_remaining(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + + initialize(new_p, new_q, new_g); + } + +/* +* Decode PEM encoded parameters +*/ +void DL_Group::PEM_decode(const std::string& pem) + { + std::string label; + + auto ber = unlock(PEM_Code::decode(pem, label)); + + if(label == "DH PARAMETERS") + BER_decode(ber, PKCS_3); + else if(label == "DSA PARAMETERS") + BER_decode(ber, ANSI_X9_57); + else if(label == "X942 DH PARAMETERS") + BER_decode(ber, ANSI_X9_42); + else + throw Decoding_Error("DL_Group: Invalid PEM label " + label); + } + +/* +* Create generator of the q-sized subgroup (DSA style generator) +*/ +BigInt DL_Group::make_dsa_generator(const BigInt& p, const BigInt& q) + { + const BigInt e = (p - 1) / q; + + if(e == 0 || (p - 1) % q > 0) + throw std::invalid_argument("make_dsa_generator q does not divide p-1"); + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + BigInt g = power_mod(PRIMES[i], e, p); + if(g > 1) + return g; + } + + throw Internal_Error("DL_Group: Couldn't create a suitable generator"); + } + +} diff --git a/src/lib/pubkey/dl_group/dl_group.h b/src/lib/pubkey/dl_group/dl_group.h new file mode 100644 index 000000000..e219bdcbd --- /dev/null +++ b/src/lib/pubkey/dl_group/dl_group.h @@ -0,0 +1,170 @@ +/* +* Discrete Logarithm Group +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DL_PARAM_H__ +#define BOTAN_DL_PARAM_H__ + +#include +#include + +namespace Botan { + +/** +* This class represents discrete logarithm groups. It holds a prime p, +* a prime q = (p-1)/2 and g = x^((p-1)/q) mod p. +*/ +class BOTAN_DLL DL_Group + { + public: + + /** + * Get the prime p. + * @return prime p + */ + const BigInt& get_p() const; + + /** + * Get the prime q. + * @return prime q + */ + const BigInt& get_q() const; + + /** + * Get the base g. + * @return base g + */ + const BigInt& get_g() const; + + /** + * The DL group encoding format variants. + */ + enum Format { + ANSI_X9_42, + ANSI_X9_57, + PKCS_3, + + DSA_PARAMETERS = ANSI_X9_57, + DH_PARAMETERS = ANSI_X9_42, + X942_DH_PARAMETERS = ANSI_X9_42, + PKCS3_DH_PARAMETERS = PKCS_3 + }; + + /** + * Determine the prime creation for DL groups. + */ + enum PrimeType { Strong, Prime_Subgroup, DSA_Kosherizer }; + + /** + * Perform validity checks on the group. + * @param rng the rng to use + * @param strong whether to perform stronger by lengthier tests + * @return true if the object is consistent, false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, bool strong) const; + + /** + * Encode this group into a string using PEM encoding. + * @param format the encoding format + * @return string holding the PEM encoded group + */ + std::string PEM_encode(Format format) const; + + /** + * Encode this group into a string using DER encoding. + * @param format the encoding format + * @return string holding the DER encoded group + */ + std::vector DER_encode(Format format) const; + + /** + * Decode a DER/BER encoded group into this instance. + * @param ber a vector containing the DER/BER encoded group + * @param format the format of the encoded group + */ + void BER_decode(const std::vector& ber, + Format format); + + /** + * Decode a PEM encoded group into this instance. + * @param pem the PEM encoding of the group + */ + void PEM_decode(const std::string& pem); + + /** + * Construct a DL group with uninitialized internal value. + * Use this constructor is you wish to set the groups values + * from a DER or PEM encoded group. + */ + DL_Group(); + + /** + * Construct a DL group that is registered in the configuration. + * @param name the name that is configured in the global configuration + * for the desired group. If no configuration file is specified, + * the default values from the file policy.cpp will be used. For instance, + * use "modp/ietf/768" as name. + */ + DL_Group(const std::string& name); + + /** + * Create a new group randomly. + * @param rng the random number generator to use + * @param type specifies how the creation of primes p and q shall + * be performed. If type=Strong, then p will be determined as a + * safe prime, and q will be chosen as (p-1)/2. If + * type=Prime_Subgroup and qbits = 0, then the size of q will be + * determined according to the estimated difficulty of the DL + * problem. If type=DSA_Kosherizer, DSA primes will be created. + * @param pbits the number of bits of p + * @param qbits the number of bits of q. Leave it as 0 to have + * the value determined according to pbits. + */ + DL_Group(RandomNumberGenerator& rng, PrimeType type, + size_t pbits, size_t qbits = 0); + + /** + * Create a DSA group with a given seed. + * @param rng the random number generator to use + * @param seed the seed to use to create the random primes + * @param pbits the desired bit size of the prime p + * @param qbits the desired bit size of the prime q. + */ + DL_Group(RandomNumberGenerator& rng, + const std::vector& seed, + size_t pbits = 1024, size_t qbits = 0); + + /** + * Create a DL group. The prime q will be determined according to p. + * @param p the prime p + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& g); + + /** + * Create a DL group. + * @param p the prime p + * @param q the prime q + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& q, const BigInt& g); + + /** + * Return PEM representation of named DL group + */ + static const char* PEM_for_named_group(const std::string& name); + private: + static BigInt make_dsa_generator(const BigInt&, const BigInt&); + + void init_check() const; + void initialize(const BigInt&, const BigInt&, const BigInt&); + bool initialized; + BigInt p, q, g; + }; + +} + +#endif diff --git a/src/lib/pubkey/dl_group/info.txt b/src/lib/pubkey/dl_group/info.txt new file mode 100644 index 000000000..26c6f12ca --- /dev/null +++ b/src/lib/pubkey/dl_group/info.txt @@ -0,0 +1,10 @@ +define DL_GROUP 20131128 + + +asn1 +bigint +filters +libstate +numbertheory +pem + diff --git a/src/lib/pubkey/dl_group/named.cpp b/src/lib/pubkey/dl_group/named.cpp new file mode 100644 index 000000000..df44f026b --- /dev/null +++ b/src/lib/pubkey/dl_group/named.cpp @@ -0,0 +1,360 @@ +/* +* List of discrete log groups +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const char* DL_Group::PEM_for_named_group(const std::string& name) + { + if(name == "modp/ietf/1024") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIBCgKBgQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5si" + "UUoIeY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummN+1r" + "C/9ctvQGt+3uOGv7Womfpa6fJBF8Sx/mSShmUezmU4H//////////wIBAgKBgH//" + "////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6AQXfUx2JzZEopQQ8xxoCbvfK" + "jNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9jeiYhdNMb9rWF/65begNb9vcc" + "Nf2tRM/S10+SCL4lj/MklDMo9nMpwP//////////" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/1024") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIBCgKBgQDurwq5rbON1pwz+Ar6j8XoYHJhh3X/PAueojFMnCVldtZ033SW6oHT" + "ODtIE9aSxuDg1djiULmL5I5JXB1gidrRXcfXtGFU1rbOjvStabFdSYJVmyl7zxiF" + "xSn1ZmYOV+xo7bw8BXJswC/Uy/SXbqqa/VE4/oN2Q1ufxh0vwOsG4wIBAgKBgHdX" + "hVzW2cbrThn8BX1H4vQwOTDDuv+eBc9RGKZOErK7azpvukt1QOmcHaQJ60ljcHBq" + "7HEoXMXyRySuDrBE7Wiu4+vaMKprW2dHela02K6kwSrNlL3njELilPqzMwcr9jR2" + "3h4CuTZgF+pl+ku3VU1+qJx/Qbshrc/jDpfgdYNx" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/ietf/1536") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIBigKBwQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5si" + "UUoIeY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummN+1r" + "C/9ctvQGt+3uOGv7Womfpa6fJBF8Sx/mSShmUezkWz3CAHy4oWO/BZjaSDYcVdOa" + "aRY/qP0kz1+DZV0j3KOtlhxi81YghVK7ntUpB3CWlm1nDDVOSryYBPF0bAjKI3Mn" + "//////////8CAQICgcB//////////+SH7VEQtGEaYmMxRcBuDmiUgScERTPmOgEF" + "31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Catrao4SLyQtq7MS8/Y3om" + "IXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/zJJQzKPZyLZ7hAD5cULHfgsxt" + "JBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqldz2qUg7hLSzazhhqnJV5MAni6" + "NgRlEbmT//////////8=" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/1536") + return + "-----BEGIN DH PARAMETERS-----" + "MIHHAoHBAJ3vPK+5OSd6sfEqhheke7vbpR30maxMgL7uqWFLGcxNX09fVW4ny95R" + "xqlL5GB6KRVYkDug0PhDgLZVu5oi6NzfAop87Gfw0IE0sci5eYkUm2CeC+O6tj1H" + "VIOB28Wx/HZOP0tT3Z2hFYv9PiucjPVu3wGVOTSWJ9sv1T0kt8SGZXcuQ31sf4zk" + "QnNK98y3roN8Jkrjqb64f4ov6bi1KS5aAh//XpFHnoznoowkQsbzFRgPk0maI03P" + "duP+0TX5uwIBAg==" + "-----END DH PARAMETERS-----"; + + if(name == "modp/ietf/2048") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIICDAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAgKCAQB//////////+SH7VEQtGEa" + "YmMxRcBuDmiUgScERTPmOgEF31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4ob" + "p/Catrao4SLyQtq7MS8/Y3omIXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/z" + "JJQzKPZyLZ7hAD5cULHfgsxtJBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqld" + "z2qUg7hLSzazhhqnJV5MAni6NgRlDBC+GUgvIxcbZx3xzzuWDAdDAc2TwdF2A9FH" + "2uKu+DemKWTvFeX7SqwLjBzKpL51SrVyiukTDEx9AogKuUctRVZVNH//////////" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/2048") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIICDAKCAQEArGvbQTJKmpvxZt5eE4lYL69ytmUZh+4H/DGSlD21YFCjcynLtKCZ" + "7YGT4HV3Z6E91SMSq0sDMQ3Nf0ip2gT9UOgIOWntt2ewz2CVF5oWOrNmGgX71fqq" + "6CkYqZYvC5O4Vfl5k+yXXuqoDXQK2/T/dHNZ0EHVwz6nHSgeRGsUdzvKl7Q6I/uA" + "Fna9IHpDbGSB8dK5B4cXRhpbnTLmiPh3SFRFI7UksNV9Xqd6J3XS7PoDLPvb9S+z" + "eGFgJ5AE5Xrmr4dOcwPOUymczAQce8MI2CpWmPOo0MOCca41+Onb+7aUtcgD2J96" + "5DXeI21SX1R1m2XjcvzWjvIPpxEfnkr/cwIBAgKCAQBWNe2gmSVNTfizby8JxKwX" + "17lbMozD9wP+GMlKHtqwKFG5lOXaUEz2wMnwOruz0J7qkYlVpYGYhua/pFTtAn6o" + "dAQctPbbs9hnsEqLzQsdWbMNAv3q/VV0FIxUyxeFydwq/LzJ9kuvdVQGugVt+n+6" + "OazoIOrhn1OOlA8iNYo7neVL2h0R/cALO16QPSG2MkD46VyDw4ujDS3OmXNEfDuk" + "KiKR2pJYar6vU70Tuul2fQGWfe36l9m8MLATyAJyvXNXw6c5gecplM5mAg494YRs" + "FStMedRoYcE41xr8dO3920pa5AHsT71yGu8RtqkvqjrNsvG5fmtHeQfTiI/PJX+5" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/ietf/3072") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIDDAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS" + "yv//////////AgECAoIBgH//////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6" + "AQXfUx2JzZEopQQ8xxoCbvfKjNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9j" + "eiYhdNMb9rWF/65begNb9vccNf2tRM/S10+SCL4lj/MklDMo9nItnuEAPlxQsd+C" + "zG0kGw4q6c00ix/UfpJnr8GyrpHuUdbLDjF5qxBCqV3PapSDuEtLNrOGGqclXkwC" + "eLo2BGUMEL4ZSC8jFxtnHfHPO5YMB0MBzZPB0XYD0Ufa4q74N6YpZO8V5ftKrAuM" + "HMqkvnVKtXKK6RMMTH0CiAq5Ry1FVWIW1pmLhoIoPRnUKpDV745dMnZ9woIsbfeF" + "RXU4q66DBj7Zy4fC03DyY9X610ZthJnrj0ZKcCUSsM7ncekTDWl3NfiX/QNsxQQy" + "bDsBOZ9kNTIpD5WMC72QBl3wi6u9MK62O4TEYF1so3EEcSfQOnLVmKHtrf5wfohH" + "JcFokFSdaWV//////////w==" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/3072") + return + "-----BEGIN DH PARAMETERS-----" + "MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS" + "yv//////////AgEF" + "-----END DH PARAMETERS-----"; + + if(name == "modp/ietf/4096") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIEDAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQICggIA" + "f//////////kh+1RELRhGmJjMUXAbg5olIEnBEUz5joBBd9THYnNkSilBDzHGgJu" + "98qM2eadIY2YFYU2+S+KG6fwmra2qOEi8kLauzEvP2N6JiF00xv2tYX/rlt6A1v2" + "9xw1/a1Ez9LXT5IIviWP8ySUMyj2ci2e4QA+XFCx34LMbSQbDirpzTSLH9R+kmev" + "wbKuke5R1ssOMXmrEEKpXc9qlIO4S0s2s4YapyVeTAJ4ujYEZQwQvhlILyMXG2cd" + "8c87lgwHQwHNk8HRdgPRR9rirvg3pilk7xXl+0qsC4wcyqS+dUq1corpEwxMfQKI" + "CrlHLUVVYhbWmYuGgig9GdQqkNXvjl0ydn3Cgixt94VFdTirroMGPtnLh8LTcPJj" + "1frXRm2EmeuPRkpwJRKwzudx6RMNaXc1+Jf9A2zFBDJsOwE5n2Q1MikPlYwLvZAG" + "XfCLq70wrrY7hMRgXWyjcQRxJ9A6ctWYoe2t/nB+iEclwWiQVJCEAI05HglTw/Nr" + "xDjNCF7dLZNM4ZOMNXpxHg1KNBpbCoXtEsH05RVqJnRt3eFtgm9HfJdHfgoP32VT" + "FD4so6c14C7M2Usn0Ehh0RGd0MMorfP2j7CUuGdxa9fcDe67ELgkDmgDSJPq2C1U" + "ydp1TEbH7uDDf9vuSFNgR6b6GuSaAxjM//////////8=" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/4096") + return + "-----BEGIN DH PARAMETERS-----" + "MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQU=" + "-----END DH PARAMETERS-----"; + + if(name == "modp/ietf/6144") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIGDAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA" + "JP//////////AoIDAH//////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6AQXf" + "Ux2JzZEopQQ8xxoCbvfKjNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9jeiYh" + "dNMb9rWF/65begNb9vccNf2tRM/S10+SCL4lj/MklDMo9nItnuEAPlxQsd+CzG0k" + "Gw4q6c00ix/UfpJnr8GyrpHuUdbLDjF5qxBCqV3PapSDuEtLNrOGGqclXkwCeLo2" + "BGUMEL4ZSC8jFxtnHfHPO5YMB0MBzZPB0XYD0Ufa4q74N6YpZO8V5ftKrAuMHMqk" + "vnVKtXKK6RMMTH0CiAq5Ry1FVWIW1pmLhoIoPRnUKpDV745dMnZ9woIsbfeFRXU4" + "q66DBj7Zy4fC03DyY9X610ZthJnrj0ZKcCUSsM7ncekTDWl3NfiX/QNsxQQybDsB" + "OZ9kNTIpD5WMC72QBl3wi6u9MK62O4TEYF1so3EEcSfQOnLVmKHtrf5wfohHJcFo" + "kFSQhACNOR4JU8Pza8Q4zQhe3S2TTOGTjDV6cR4NSjQaWwqF7RLB9OUVaiZ0bd3h" + "bYJvR3yXR34KD99lUxQ+LKOnNeAuzNlLJ9BIYdERndDDKK3z9o+wlLhncWvX3A3u" + "uxC4JA5oA0iT6tgtVMnadUxGx+7gw3/b7khTYEem+hrkmgFCSRth/VppPjgTYOpu" + "WTATI29kuo87Ht0b3vx/ygNWzymHcu2cF6CYANdYNSn2yBPsGIvLk9hDLUSMbR9t" + "9efNinaiZzZdZ2pdje2/iiPzZhKlmZAoqJXr16E33HoAm8ZpX6zB5QDjJcl2eBl1" + "Cui5DoH6QWvnNzp/e2qvOBejTAZBWtQgGMgFjk8s8+S/32P0eZHUvT8bZkRfB46i" + "2/+sLWKl6gPZFaCqVWZHtr9fpHDsCmYvaQfAG/BTy4r3eU3xlANQ6sXb4u07eqhV" + "HsUP3/h1jOZY0Ynqrm0rZPYXeUsZHD/0a7ceAjQCH0ezH6Qwdwlflq2Fujprc0p8" + "jzbmIBJ//////////wIBAg==" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/6144") + return + "-----BEGIN DH PARAMETERS-----" + "MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA" + "JP//////////AgEF" + "-----END DH PARAMETERS-----"; + + if(name == "modp/ietf/8192") + return + "-----BEGIN X942 DH PARAMETERS-----" + "MIIIDAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R" + "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk" + "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw" + "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4" + "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i" + "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU" + "38gfVuiAuW5xYMmA3Zjt09///////////wKCBAB//////////+SH7VEQtGEaYmMx" + "RcBuDmiUgScERTPmOgEF31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Ca" + "trao4SLyQtq7MS8/Y3omIXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/zJJQz" + "KPZyLZ7hAD5cULHfgsxtJBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqldz2qU" + "g7hLSzazhhqnJV5MAni6NgRlDBC+GUgvIxcbZx3xzzuWDAdDAc2TwdF2A9FH2uKu" + "+DemKWTvFeX7SqwLjBzKpL51SrVyiukTDEx9AogKuUctRVViFtaZi4aCKD0Z1CqQ" + "1e+OXTJ2fcKCLG33hUV1OKuugwY+2cuHwtNw8mPV+tdGbYSZ649GSnAlErDO53Hp" + "Ew1pdzX4l/0DbMUEMmw7ATmfZDUyKQ+VjAu9kAZd8IurvTCutjuExGBdbKNxBHEn" + "0Dpy1Zih7a3+cH6IRyXBaJBUkIQAjTkeCVPD82vEOM0IXt0tk0zhk4w1enEeDUo0" + "GlsKhe0SwfTlFWomdG3d4W2Cb0d8l0d+Cg/fZVMUPiyjpzXgLszZSyfQSGHREZ3Q" + "wyit8/aPsJS4Z3Fr19wN7rsQuCQOaANIk+rYLVTJ2nVMRsfu4MN/2+5IU2BHpvoa" + "5JoBQkkbYf1aaT44E2DqblkwEyNvZLqPOx7dG978f8oDVs8ph3LtnBegmADXWDUp" + "9sgT7BiLy5PYQy1EjG0fbfXnzYp2omc2XWdqXY3tv4oj82YSpZmQKKiV69ehN9x6" + "AJvGaV+sweUA4yXJdngZdQrouQ6B+kFr5zc6f3tqrzgXo0wGQVrUIBjIBY5PLPPk" + "v99j9HmR1L0/G2ZEXweOotv/rC1ipeoD2RWgqlVmR7a/X6Rw7ApmL2kHwBvwU8uK" + "93lN8ZQDUOrF2+LtO3qoVR7FD9/4dYzmWNGJ6q5tK2T2F3lLGRw/9Gu3HgI0Ah9H" + "sx+kMHcJX5athbo6a3NKfI823wisulHJN4l/cvIcO75bVJlvxmxfYmg53JjdHeQZ" + "W0bO6YA6D9PfxX4j9pK7e0m10hIzHVWxzi1yerQaEdo6FfjkvBHHi2XxzrKW8f7c" + "X35CRWyRERcCUgG+A4n1q9QNEfhjmjn+MjZ1GDWl5eRDF8HC7v1Opb/RYEP0PLQZ" + "gfat7p0DFZ562dE8UzaVCfwfonwW75iHcDpVtRsiy/RM0BKu4LJ5jmKEI0KO/NWk" + "DK72v1DY6ohev3Omuf15teGPZ9E0GsgjenXDz8kgBKHFpA42a8RNABdq9xwV5IyG" + "034BNyPKrHIjqzv01U8YKHE7K0pv5A+rdEBctziwZMBuzHbp7///////////AgEC" + "-----END X942 DH PARAMETERS-----"; + + if(name == "modp/srp/8192") + return + "-----BEGIN DH PARAMETERS-----" + "MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R" + "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk" + "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw" + "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4" + "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i" + "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU" + "38gfVuiAuW5xYMmA3Zjt09///////////wIBEw==" + "-----END DH PARAMETERS-----"; + + if(name == "dsa/jce/1024") + return + "-----BEGIN DSA PARAMETERS-----" + "MIIBHgKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9" + "jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX" + "58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8V" + "IwvMspK5gqLrhAvwWBz1AoGARpYDUS4wJ4zTlHWV2yLuyYJqYyKtyXNE9B10DDJX" + "JMj577qn1NgD/4xgnc0QDrxb38+tfGpCX66nhuogUOvpg1HqH9of3yTWlHqmuaoj" + "dmlTgC9NfUqOy6BtGXaKJJH/sW0O+cQ6mbX3FnL/bwoktETQc20E04oaEyLa9s3Y" + "jJ0=" + "-----END DSA PARAMETERS-----"; + + if(name == "dsa/botan/2048") + return + "-----BEGIN DSA PARAMETERS-----" + "MIICLAKCAQEAkcSKT9+898Aq6V59oSYSK13Shk9Vm4fo50oobVL1m9HeaN/WRdDg" + "DGDAgAMYkZgDdO61lKUyv9Z7mgnqxLhmOgeRDmjzlGX7cEDSXfE5MuusQ0elMOy6" + "YchU+biA08DDZgCAWHxFVm2t4mvVo5S+CTtMDyS1r/747GxbPlf7iQJam8FnaZMh" + "MeFtPJTvyrGNDfBhIDzFPmEDvHLVWUv9QMplOA9EqahR3LB1SV/AM6ilgHGhvXj+" + "BS9mVVZI60txnSr+i0iA+NrW8VgYuhePiSdMhwvpuW6wjEbEAEDMLv4d+xsYaN0x" + "nePDSjKmOrbrEiQgmkGWgMx5AtFyjU354QIhAIzX1FD4bwrZTu5M5GmodW0evRBY" + "JBlD6v+ws1RYXpJNAoIBAA2fXgdhtNvRgz1qsalhoJlsXyIwP3LYTBQPZ8Qx2Uq1" + "cVvqgaDJjTnOS8941rnryJXTT+idlAkdWEhhXvFfXobxHZb2yWniA936WDVkIKSc" + "tES1lbkBqTPP4HZ7WU8YoHt/kd7NukRriJkPePL/kfL+fNQ/0uRtGOraH3u2YCxh" + "f27zpLKE8v2boQo2BC3o+oeiyjZZf+yBFXoUheRAQd8CgwERy4gLvm7UlIFIhvll" + "zcMTX1zPE4Nyi/ZbgG+WksCxDWxMCcdabKO0ATyxarLBBfa+I66pAA6rIXiYX5cs" + "mAV+HIbkTnIYaI6krg82NtzKdFydzU5q/7Z8y8E9YTE=" + "-----END DSA PARAMETERS-----"; + + if(name == "dsa/botan/3072") + return + "-----BEGIN DSA PARAMETERS-----" + "MIIDLAKCAYEA5LUIgHWWY1heFCRgyi2d/xMviuTIQN2jomZoiRJP5WOLhOiim3rz" + "+hIJvmv8S1By7Tsrc4e68/hX9HioAijvNgC3az3Pth0g00RlslBtLK+H3259wM6R" + "vS0Wekb2rcwxxTHk+cervbkq3fNbCoBsZikqX14X6WTdCZkDczrEKKs12A6m9oW/" + "uovkBo5UGK5eytno/wc94rY+Tn6tNciptwtb1Hz7iNNztm83kxk5sKtxvVWVgJCG" + "2gFVM30YWg5Ps2pRmxtiArhZHmACRJzxzTpmOE9tIHOxzXO+ypO68eGmEX0COPIi" + "rh7X/tGFqJDn9n+rj+uXU8wTSlGD3+h64llfe1wtn7tCJJ/dWVE+HTOWs+sv2GaE" + "8oWoRI/nV6ApiBxAdguU75Gb35dAw4OJWZ7FGm6btRmo4GhJHpzgovz+PLYNZs8N" + "+tIKjsaEBIaEphREV1vRck1zUrRKdgB3s71r04XOWwpyUMwL92jagpI4Buuc+7E4" + "hDcxthggjHWbAiEAs+vTZOxp74zzuvZDt1c0sWM5suSeXN4bWcHp+0DuDFsCggGA" + "K+0h7vg5ZKIwrom7px2ffDnFL8gim047x+WUTTKdoQ8BDqyee69sAJ/E6ylgcj4r" + "Vt9GY+TDrIAOkljeL3ZJ0gZ4KJP4Ze/KSY0u7zAHTqXop6smJxKk2UovOwuaku5A" + "D7OKPMWaXcfkNtXABLIuNQKDgbUck0B+sy1K4P1Cy0XhLQ7O6KJiOO3iCCp7FSIR" + "PGbO+NdFxs88uUX4TS9N4W1Epx3hmCcOE/A1U8iLjTI60LlIob8hA6lJl5tu0W+1" + "88lT2Vt8jojKZ9z1pjb7nKOdkkIV96iE7Wx+48ltjZcVQnl0t8Q1EoLhPTdz99KL" + "RS8QiSoTx1hzKN6kgntrNpsqjcFyrcWD9R8qZZjFSD5bxGewL5HQWcQC0Y4sJoD3" + "dqoG9JKAoscsF8xC1bbnQMXEsas8UcLtCSviotiwU65Xc9FCXtKwjwbi3VBZLfGk" + "eMFVkc39EVZP+I/zi3IdQjkv2kcyEtz9jS2IqXagCv/m//tDCjWeZMorNRyiQSOU" + "-----END DSA PARAMETERS-----"; + + return nullptr; + } + +} diff --git a/src/lib/pubkey/dlies/dlies.cpp b/src/lib/pubkey/dlies/dlies.cpp new file mode 100644 index 000000000..715b55a36 --- /dev/null +++ b/src/lib/pubkey/dlies/dlies.cpp @@ -0,0 +1,146 @@ +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* DLIES_Encryptor Constructor +*/ +DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& key, + KDF* kdf_obj, + MessageAuthenticationCode* mac_obj, + size_t mac_kl) : + ka(key, "Raw"), + kdf(kdf_obj), + mac(mac_obj), + mac_keylen(mac_kl) + { + my_key = key.public_value(); + } + +DLIES_Encryptor::~DLIES_Encryptor() + { + delete kdf; + delete mac; + } + +/* +* DLIES Encryption +*/ +std::vector DLIES_Encryptor::enc(const byte in[], size_t length, + RandomNumberGenerator&) const + { + if(length > maximum_input_size()) + throw Invalid_Argument("DLIES: Plaintext too large"); + if(other_key.empty()) + throw Invalid_State("DLIES: The other key was never set"); + + secure_vector out(my_key.size() + length + mac->output_length()); + buffer_insert(out, 0, my_key); + buffer_insert(out, my_key.size(), in, length); + + secure_vector vz(my_key.begin(), my_key.end()); + vz += ka.derive_key(0, other_key).bits_of(); + + const size_t K_LENGTH = length + mac_keylen; + OctetString K = kdf->derive_key(K_LENGTH, vz); + + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + byte* C = &out[my_key.size()]; + + xor_buf(C, K.begin() + mac_keylen, length); + mac->set_key(K.begin(), mac_keylen); + + mac->update(C, length); + for(size_t j = 0; j != 8; ++j) + mac->update(0); + + mac->final(C + length); + + return unlock(out); + } + +/* +* Set the other parties public key +*/ +void DLIES_Encryptor::set_other_key(const std::vector& ok) + { + other_key = ok; + } + +/* +* Return the max size, in bytes, of a message +*/ +size_t DLIES_Encryptor::maximum_input_size() const + { + return 32; + } + +/* +* DLIES_Decryptor Constructor +*/ +DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& key, + KDF* kdf_obj, + MessageAuthenticationCode* mac_obj, + size_t mac_kl) : + ka(key, "Raw"), + kdf(kdf_obj), + mac(mac_obj), + mac_keylen(mac_kl) + { + my_key = key.public_value(); + } + +DLIES_Decryptor::~DLIES_Decryptor() + { + delete kdf; + delete mac; + } + +/* +* DLIES Decryption +*/ +secure_vector DLIES_Decryptor::dec(const byte msg[], size_t length) const + { + if(length < my_key.size() + mac->output_length()) + throw Decoding_Error("DLIES decryption: ciphertext is too short"); + + const size_t CIPHER_LEN = length - my_key.size() - mac->output_length(); + + std::vector v(msg, msg + my_key.size()); + + secure_vector C(msg + my_key.size(), msg + my_key.size() + CIPHER_LEN); + + secure_vector T(msg + my_key.size() + CIPHER_LEN, + msg + my_key.size() + CIPHER_LEN + mac->output_length()); + + secure_vector vz(msg, msg + my_key.size()); + vz += ka.derive_key(0, v).bits_of(); + + const size_t K_LENGTH = C.size() + mac_keylen; + OctetString K = kdf->derive_key(K_LENGTH, vz); + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + + mac->set_key(K.begin(), mac_keylen); + mac->update(C); + for(size_t j = 0; j != 8; ++j) + mac->update(0); + secure_vector T2 = mac->final(); + if(T != T2) + throw Decoding_Error("DLIES: message authentication failed"); + + xor_buf(C, K.begin() + mac_keylen, C.size()); + + return C; + } + +} diff --git a/src/lib/pubkey/dlies/dlies.h b/src/lib/pubkey/dlies/dlies.h new file mode 100644 index 000000000..9739afeb2 --- /dev/null +++ b/src/lib/pubkey/dlies/dlies.h @@ -0,0 +1,71 @@ +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DLIES_H__ +#define BOTAN_DLIES_H__ + +#include +#include +#include + +namespace Botan { + +/** +* DLIES Encryption +*/ +class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor + { + public: + DLIES_Encryptor(const PK_Key_Agreement_Key&, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + ~DLIES_Encryptor(); + + void set_other_key(const std::vector&); + private: + std::vector enc(const byte[], size_t, + RandomNumberGenerator&) const; + + size_t maximum_input_size() const; + + std::vector other_key, my_key; + + PK_Key_Agreement ka; + KDF* kdf; + MessageAuthenticationCode* mac; + size_t mac_keylen; + }; + +/** +* DLIES Decryption +*/ +class BOTAN_DLL DLIES_Decryptor : public PK_Decryptor + { + public: + DLIES_Decryptor(const PK_Key_Agreement_Key&, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + ~DLIES_Decryptor(); + + private: + secure_vector dec(const byte[], size_t) const; + + std::vector my_key; + + PK_Key_Agreement ka; + KDF* kdf; + MessageAuthenticationCode* mac; + size_t mac_keylen; + }; + +} + +#endif diff --git a/src/lib/pubkey/dlies/info.txt b/src/lib/pubkey/dlies/info.txt new file mode 100644 index 000000000..b159cc546 --- /dev/null +++ b/src/lib/pubkey/dlies/info.txt @@ -0,0 +1,7 @@ +define DLIES 20131128 + + +kdf +libstate +mac + diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp new file mode 100644 index 000000000..5d56d6b89 --- /dev/null +++ b/src/lib/pubkey/dsa/dsa.cpp @@ -0,0 +1,143 @@ +/* +* DSA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +namespace Botan { + +/* +* DSA_PublicKey Constructor +*/ +DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* Create a DSA private key +*/ +DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + x = BigInt::random_integer(rng, 2, group_q() - 1); + + y = power_mod(group_g(), x, group_p()); + + if(x_arg == 0) + gen_check(rng); + else + load_check(rng); + } + +DSA_PrivateKey::DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + y = power_mod(group_g(), x, group_p()); + + load_check(rng); + } + +/* +* Check Private DSA Parameters +*/ +bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +DSA_Signature_Operation::DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + q(dsa.group_q()), + x(dsa.get_x()), + powermod_g_p(dsa.group_g(), dsa.group_p()), + mod_q(dsa.group_q()) + { + } + +secure_vector +DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + BigInt i(msg, msg_len); + BigInt r = 0, s = 0; + + while(r == 0 || s == 0) + { + BigInt k; + do + k.randomize(rng, q.bits()); + while(k >= q); + + auto future_r = std::async(std::launch::async, + [&]() { return mod_q.reduce(powermod_g_p(k)); }); + + s = inverse_mod(k, q); + r = future_r.get(); + s = mod_q.multiply(s, mul_add(x, r, i)); + } + + secure_vector output(2*q.bytes()); + r.binary_encode(&output[output.size() / 2 - r.bytes()]); + s.binary_encode(&output[output.size() - s.bytes()]); + return output; + } + +DSA_Verification_Operation::DSA_Verification_Operation(const DSA_PublicKey& dsa) : + q(dsa.group_q()), y(dsa.get_y()) + { + powermod_g_p = Fixed_Base_Power_Mod(dsa.group_g(), dsa.group_p()); + powermod_y_p = Fixed_Base_Power_Mod(y, dsa.group_p()); + mod_p = Modular_Reducer(dsa.group_p()); + mod_q = Modular_Reducer(dsa.group_q()); + } + +bool DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const BigInt& q = mod_q.get_modulus(); + + if(sig_len != 2*q.bytes() || msg_len > q.bytes()) + return false; + + BigInt r(sig, q.bytes()); + BigInt s(sig + q.bytes(), q.bytes()); + BigInt i(msg, msg_len); + + if(r <= 0 || r >= q || s <= 0 || s >= q) + return false; + + s = inverse_mod(s, q); + + auto future_s_i = std::async(std::launch::async, + [&]() { return powermod_g_p(mod_q.multiply(s, i)); }); + + BigInt s_r = powermod_y_p(mod_q.multiply(s, r)); + BigInt s_i = future_s_i.get(); + + s = mod_p.multiply(s_i, s_r); + + return (mod_q.reduce(s) == r); + } + +} diff --git a/src/lib/pubkey/dsa/dsa.h b/src/lib/pubkey/dsa/dsa.h new file mode 100644 index 000000000..7d51cfdd0 --- /dev/null +++ b/src/lib/pubkey/dsa/dsa.h @@ -0,0 +1,107 @@ +/* +* DSA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DSA_H__ +#define BOTAN_DSA_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* DSA Public Key +*/ +class BOTAN_DLL DSA_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "DSA"; } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_57; } + size_t message_parts() const { return 2; } + size_t message_part_size() const { return group_q().bytes(); } + size_t max_input_bits() const { return group_q().bits(); } + + DSA_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + } + + DSA_PublicKey(const DL_Group& group, const BigInt& y); + protected: + DSA_PublicKey() {} + }; + +/** +* DSA Private Key +*/ +class BOTAN_DLL DSA_PrivateKey : public DSA_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng); + + DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& private_key = 0); + + bool check_key(RandomNumberGenerator& rng, bool strong) const; + }; + +/** +* Object that can create a DSA signature +*/ +class BOTAN_DLL DSA_Signature_Operation : public PK_Ops::Signature + { + public: + DSA_Signature_Operation(const DSA_PrivateKey& dsa); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return q.bits(); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const BigInt& q; + const BigInt& x; + Fixed_Base_Power_Mod powermod_g_p; + Modular_Reducer mod_q; + }; + +/** +* Object that can verify a DSA signature +*/ +class BOTAN_DLL DSA_Verification_Operation : public PK_Ops::Verification + { + public: + DSA_Verification_Operation(const DSA_PublicKey& dsa); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return q.bits(); } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const BigInt& q; + const BigInt& y; + + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p, mod_q; + }; + +} + +#endif diff --git a/src/lib/pubkey/dsa/info.txt b/src/lib/pubkey/dsa/info.txt new file mode 100644 index 000000000..a3f2a1ee4 --- /dev/null +++ b/src/lib/pubkey/dsa/info.txt @@ -0,0 +1,9 @@ +define DSA 20131128 + + +dl_algo +dl_group +keypair +libstate +numbertheory + diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp new file mode 100644 index 000000000..9143543e4 --- /dev/null +++ b/src/lib/pubkey/ec_group/ec_group.cpp @@ -0,0 +1,134 @@ +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +EC_Group::EC_Group(const OID& domain_oid) + { + const char* pem = PEM_for_named_group(OIDS::lookup(domain_oid)); + + if(!pem) + throw Lookup_Error("No ECC domain data for " + domain_oid.as_string()); + + *this = EC_Group(pem); + oid = domain_oid.as_string(); + } + +EC_Group::EC_Group(const std::string& str) + { + if(str == "") + return; // no initialization / uninitialized + + try + { + std::vector ber = + unlock(PEM_Code::decode_check_label(str, "EC PARAMETERS")); + + *this = EC_Group(ber); + } + catch(Decoding_Error) // hmm, not PEM? + { + *this = EC_Group(OIDS::lookup(str)); + } + } + +EC_Group::EC_Group(const std::vector& ber_data) + { + BER_Decoder ber(ber_data); + BER_Object obj = ber.get_next_object(); + + if(obj.type_tag == NULL_TAG) + throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters"); + else if(obj.type_tag == OBJECT_ID) + { + OID dom_par_oid; + BER_Decoder(ber_data).decode(dom_par_oid); + *this = EC_Group(dom_par_oid); + } + else if(obj.type_tag == SEQUENCE) + { + BigInt p, a, b; + std::vector sv_base_point; + + BER_Decoder(ber_data) + .start_cons(SEQUENCE) + .decode_and_check(1, "Unknown ECC param version code") + .start_cons(SEQUENCE) + .decode_and_check(OID("1.2.840.10045.1.1"), + "Only prime ECC fields supported") + .decode(p) + .end_cons() + .start_cons(SEQUENCE) + .decode_octet_string_bigint(a) + .decode_octet_string_bigint(b) + .end_cons() + .decode(sv_base_point, OCTET_STRING) + .decode(order) + .decode(cofactor) + .end_cons() + .verify_end(); + + curve = CurveGFp(p, a, b); + base_point = OS2ECP(sv_base_point, curve); + } + else + throw Decoding_Error("Unexpected tag while decoding ECC domain params"); + } + +std::vector +EC_Group::DER_encode(EC_Group_Encoding form) const + { + if(form == EC_DOMPAR_ENC_EXPLICIT) + { + const size_t ecpVers1 = 1; + OID curve_type("1.2.840.10045.1.1"); + + const size_t p_bytes = curve.get_p().bytes(); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(ecpVers1) + .start_cons(SEQUENCE) + .encode(curve_type) + .encode(curve.get_p()) + .end_cons() + .start_cons(SEQUENCE) + .encode(BigInt::encode_1363(curve.get_a(), p_bytes), + OCTET_STRING) + .encode(BigInt::encode_1363(curve.get_b(), p_bytes), + OCTET_STRING) + .end_cons() + .encode(EC2OSP(base_point, PointGFp::UNCOMPRESSED), OCTET_STRING) + .encode(order) + .encode(cofactor) + .end_cons() + .get_contents_unlocked(); + } + else if(form == EC_DOMPAR_ENC_OID) + return DER_Encoder().encode(OID(get_oid())).get_contents_unlocked(); + else if(form == EC_DOMPAR_ENC_IMPLICITCA) + return DER_Encoder().encode_null().get_contents_unlocked(); + else + throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); + } + +std::string EC_Group::PEM_encode() const + { + const std::vector der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); + return PEM_Code::encode(der, "EC PARAMETERS"); + } + +} diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h new file mode 100644 index 000000000..80859bd71 --- /dev/null +++ b/src/lib/pubkey/ec_group/ec_group.h @@ -0,0 +1,148 @@ +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECC_DOMAIN_PARAMETERS_H__ +#define BOTAN_ECC_DOMAIN_PARAMETERS_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents elliptic curce domain parameters +*/ +enum EC_Group_Encoding { + EC_DOMPAR_ENC_EXPLICIT = 0, + EC_DOMPAR_ENC_IMPLICITCA = 1, + EC_DOMPAR_ENC_OID = 2 +}; + +/** +* Class representing an elliptic curve +*/ +class BOTAN_DLL EC_Group + { + public: + + /** + * Construct Domain paramers from specified parameters + * @param curve elliptic curve + * @param base_point a base point + * @param order the order of the base point + * @param cofactor the cofactor + */ + EC_Group(const CurveGFp& curve, + const PointGFp& base_point, + const BigInt& order, + const BigInt& cofactor) : + curve(curve), + base_point(base_point), + order(order), + cofactor(cofactor), + oid("") + {} + + /** + * Decode a BER encoded ECC domain parameter set + * @param ber_encoding the bytes of the BER encoding + */ + EC_Group(const std::vector& ber_encoding); + + /** + * Create an EC domain by OID (or throw if unknown) + * @param oid the OID of the EC domain to create + */ + EC_Group(const OID& oid); + + /** + * Create an EC domain from PEM encoding (as from PEM_encode), or + * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7") + * @param pem_or_oid PEM-encoded data, or an OID + */ + EC_Group(const std::string& pem_or_oid = ""); + + /** + * Create the DER encoding of this domain + * @param form of encoding to use + * @returns bytes encododed as DER + */ + std::vector DER_encode(EC_Group_Encoding form) const; + + /** + * Return the PEM encoding (always in explicit form) + * @return string containing PEM data + */ + std::string PEM_encode() const; + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + const CurveGFp& get_curve() const { return curve; } + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + const PointGFp& get_base_point() const { return base_point; } + + /** + * Return the order of the base point + * @result order of the base point + */ + const BigInt& get_order() const { return order; } + + /** + * Return the cofactor + * @result the cofactor + */ + const BigInt& get_cofactor() const { return cofactor; } + + bool initialized() const { return !base_point.is_zero(); } + + /** + * Return the OID of these domain parameters + * @result the OID + */ + std::string get_oid() const { return oid; } + + bool operator==(const EC_Group& other) const + { + return ((get_curve() == other.get_curve()) && + (get_base_point() == other.get_base_point()) && + (get_order() == other.get_order()) && + (get_cofactor() == other.get_cofactor())); + } + + /** + * Return PEM representation of named EC group + */ + static const char* PEM_for_named_group(const std::string& name); + + private: + CurveGFp curve; + PointGFp base_point; + BigInt order, cofactor; + std::string oid; + }; + +inline bool operator!=(const EC_Group& lhs, + const EC_Group& rhs) + { + return !(lhs == rhs); + } + +// For compatability with 1.8 +typedef EC_Group EC_Domain_Params; + +} + +#endif diff --git a/src/lib/pubkey/ec_group/info.txt b/src/lib/pubkey/ec_group/info.txt new file mode 100644 index 000000000..661f24473 --- /dev/null +++ b/src/lib/pubkey/ec_group/info.txt @@ -0,0 +1,10 @@ +define ECC_GROUP 20131128 + + +asn1 +ec_gfp +libstate +numbertheory +oid_lookup +pem + diff --git a/src/lib/pubkey/ec_group/named.cpp b/src/lib/pubkey/ec_group/named.cpp new file mode 100644 index 000000000..86e99db6d --- /dev/null +++ b/src/lib/pubkey/ec_group/named.cpp @@ -0,0 +1,307 @@ +/* +* List of ECC groups +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +const char* EC_Group::PEM_for_named_group(const std::string& name) + { + if(name == "secp112r1") + return + "-----BEGIN EC PARAMETERS-----" + "MHQCAQEwGgYHKoZIzj0BAQIPANt8Kr9i415mgHa+rSCLMCAEDtt8Kr9i415mgHa+" + "rSCIBA5lnvi6BDkW7t6JEXArIgQdBAlIcjmZWl7na1X5wvCYqJzlr4ckwKI+Dg/3" + "dQACDwDbfCq/YuNedijfrGVhxQIBAQ==" + "-----END EC PARAMETERS-----"; + + if(name == "secp112r2") + return + "-----BEGIN EC PARAMETERS-----" + "MHMCAQEwGgYHKoZIzj0BAQIPANt8Kr9i415mgHa+rSCLMCAEDmEnwkwF84oKqvZc" + "DvAsBA5R3vGBXbXtdPzDTIXXCQQdBEujCrXokrThZJ3QkoZDrc1G9YguN0fe826V" + "bpcCDjbfCq/YuNdZfKEFINBLAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "secp128r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGAAgEBMBwGByqGSM49AQECEQD////9////////////////MCQEEP////3/////" + "//////////wEEOh1ecEQefQ92CSZPCzuXtMEIQQWH/dSi4mbLQwoYHylLFuGz1rI" + "OVuv6xPALaKS3e16gwIRAP////4AAAAAdaMNG5A4oRUCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp128r2") + return + "-----BEGIN EC PARAMETERS-----" + "MH8CAQEwHAYHKoZIzj0BAQIRAP////3///////////////8wJAQQ1gMZmNGzu/6/" + "Wcybv/mu4QQQXu78o4DQKRncLGVYu22KXQQhBHtqpdheVymD5vsyp83rwUAntpFq" + "iU067nEG/oBfw0tEAhA/////f////74AJHIGE7WjAgEE" + "-----END EC PARAMETERS-----"; + + if(name == "secp160k1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQD////////////////////+//+sczAsBBQAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAQUAAAAAAAAAAAAAAAAAAAAAAAAAAcEKQQ7TDgs43qh" + "kqQBnnYwNvT13U1+u5OM+TUxj9zta8KChlMXM8PwPE/uAhUBAAAAAAAAAAAAAbj6" + "Ft+rmsoWtrMCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp160r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQD/////////////////////f////zAsBBT/////" + "////////////////f////AQUHJe+/FS9eotlrPifgdTUrcVl+kUEKQRKlrVojvVz" + "KEZkaYlow4u5E8v8giOmKFUxaJR9WdzJEgQjUTd6xfsyAhUBAAAAAAAAAAAAAfTI" + "+Seu08p1IlcCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp160r2") + return + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQD////////////////////+//+sczAsBBT/////" + "///////////////+//+scAQUtOE00/tZ64urVydJBGZNWvUDiLoEKQRS3LA0KToR" + "fh9P8Rsw9xmdMUTObf6v/vLjMfKW4HH6DfmYLP6n1D8uAhUBAAAAAAAAAAAAADUe" + "54aoGPOhoWsCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp192k1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD//////////////////////////v//7jcwNAQY" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAMEMQTbT/EOwFfpriawfQKAt/Q0HaXRsergbH2bLy9tnFYop4RBY9AVvoY0QIKq" + "iNleL50CGQD///////////////4m8vwXD2lGanTe/Y0CAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp192r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY" + "/////////////////////v/////////8BBhkIQUZ5ZyA5w+n6atyJDBJ/rje7MFG" + "ubEEMQQYjagOsDCQ9ny/IOtDoYgA9P8K/YL/EBIHGSuV/8jaeGMQEe1rJM3Vc/l3" + "oR55SBECGQD///////////////+Z3vg2FGvJsbTSKDECAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp224k1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHIAgEBMCgGByqGSM49AQECHQD///////////////////////////////7//+Vt" + "MDwEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAUEOQShRVszTfCZ3zD8KKFppGfp5HB1qQ9+ZQ62t6Rcfgif" + "7X+6NEKCyvvW9+MZ98CwvVniykvbVW1hpQIdAQAAAAAAAAAAAAAAAAAB3OjS7GGE" + "yvCpcXafsfcCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp224r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHIAgEBMCgGByqGSM49AQECHQD/////////////////////AAAAAAAAAAAAAAAB" + "MDwEHP////////////////////7///////////////4EHLQFCoUMBLOr9UEyVlBE" + "sLfXv9i6Jws5QyNV/7QEOQS3Dgy9a7S/fzITkLlKA8HTVsIRIjQygNYRXB0hvTdj" + "iLX3I/tMIt/mzUN1oFoHR2RE1YGZhQB+NAIdAP//////////////////FqLguPA+" + "E90pRVxcKj0CAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp256k1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQD////////////////////////////////////+" + "///8LzBEBCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQgAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEQQR5vmZ++dy7rFWgYpXOhwsHApv8" + "2y3OKNlZ8oFbFvgXmEg62ncmo8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA" + "/////////////////////rqu3OavSKA7v9JejNA2QUECAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp256r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////" + "/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6" + "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDydwN9" + "gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA" + "/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "secp384r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIIBQAIBATA8BgcqhkjOPQEBAjEA////////////////////////////////////" + "//////7/////AAAAAAAAAAD/////MGQEMP//////////////////////////////" + "///////////+/////wAAAAAAAAAA/////AQwszEvp+I+5+SYjgVr4/gtGRgdnG7+" + "gUESAxQIj1ATh1rGVjmNii7RnSqFyO3T7CrvBGEEqofKIr6LBTeOscce8yCtdG4d" + "O2KLp5uYWfdB4IJUKjhVAvJdv1UpbDpUXjhydgq3NhfeSpYmLG9dnpi/kpLcKfj0" + "Hb0omhR86doxE7XwuMAKYLHOHX6BnXpDHXyQ6g5fAjEA////////////////////" + "////////////x2NNgfQ3Ld9YGg2ySLCneuzsGWrMxSlzAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "secp521r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIIBrAIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////" + "//////////////////////////////////////////////////8wgYgEQgH/////" + "////////////////////////////////////////////////////////////////" + "/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ" + "4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8ABIGFBADGhY4GtwQE6c2e" + "PstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5" + "fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQm" + "QMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////////////" + "////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "1.3.6.1.4.1.8301.3.1.2.9.0.38") + return + "-----BEGIN EC PARAMETERS-----" + "MIIBrAIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////" + "//////////////////////////////////////////////////8wgYgEQgH/////" + "////////////////////////////////////////////////////////////////" + "/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ" + "4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8ABIGFBADGhY4GtwQE6c2e" + "PstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5" + "fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQm" + "QMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////////////" + "////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool160r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQDpXkpfc3BZ3GDfx62Vs9gTlRViDzAsBBQ0Dnvi" + "ooDrdOK+YbradF2X6PfDAAQUHliahZVCNBITT6otveyVyNhnXlgEKQS+1a8W6j9q" + "T2KTjEYx61r3vbzbwxZny0d6Go7DOPlHQWacl2MW2mMhAhUA6V5KX3NwWdxg31mR" + "1FApQJ5g/AkCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool192r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQDDAvQdkyo2zaejRjCT0Y23j85HbeGoYpcwNAQY" + "apEXQHax4OGcOcAx/oaFwcrgQOXGmijvBBhGmijvfCjMo9xyHQRPRJa8yn70FG+/" + "JckEMQTAoGR+qrakh1OwM8VssPCQCi9cSFM3X9YUtpCGar1buItfSCjBSQAC5nc/" + "ovopm48CGQDDAvQdkyo2zaejRi+enpFrW+jxAprErMECAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool224r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHIAgEBMCgGByqGSM49AQECHQDXwTSqJkNmhioYMCV10deHsJ8HV5faifV+yMD/" + "MDwEHGil5iypzmwcKZgDpsFTC1FOGCrYsAQqWcrSn0MEHCWA9jzP5EE4hwcTsakj" + "aeM+ITXSZtuzcjhsQAsEOQQNkCmtLH5c9DQII7KofcaMnkzjF0webv3uEsB9WKpW" + "93LAcm8kxrieTs2sJDVLnpnKo/bTdhQCzQIdANfBNKomQ2aGKhgwJXXQ+5jRFrxL" + "bd68o6Wnk58CAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool256r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQCp+1fboe6pvD5mCpCdg41ybjv2I9UmICggE0gd" + "H25TdzBEBCB9Wgl1/CwwV+72dTBBev/n+4BVwSbcXGzpSktE8zC12QQgJtxcbOlK" + "S0TzMLXZu9d8v5WEFilc9+HOa8zcGP+MB7YEQQSL0q65y35XyyxLSC/8gbevud4n" + "4eO9I8I6RFO9ms4yYlR++DXD2sT9l/hGGhRhHcnCd0UTLe2OVFwdVMcvBGmXAiEA" + "qftX26Huqbw+ZgqQnYONcYw5eqO1Yab3kB4OgpdIVqcCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool320r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIIBEAIBATA0BgcqhkjOPQEBAikA015HIDa8T7fhPHhe0gHgZfmPz6b29A3vT5K5" + "7HiT7Cj81BKx8bMuJzBUBCg+4wtWj7qw+IPM69RtPzu4oqc1E/XredpmGQ6whf+p" + "9JLzdal9hg60BChSCIOUnf28QtOtGYZAaIpv4T9BNJVUtJrMMdzNiEU5gW9etKyP" + "sfGmBFEEQ71+mvtT2LhSibzEjuW/5vIBN9EKCH6254ceKhClmccQr40NOeIGERT9" + "0FVF7BzIq0CTJH93J14HQ//tEXGC6qnHeHeqrGrH01JF0WkujuECKQDTXkcgNrxP" + "t+E8eF7SAeBl+Y/PpbaPEqMtSC7H7oZY6YaRVVtExZMRAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool384r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIIBQAIBATA8BgcqhkjOPQEBAjEAjLkegqM4bSgPXW9+UOZB3xUvcQntVFa0ErHa" + "GX+3ESOs06cpkB0acYdHABMxB+xTMGQEMHvDgsY9jBUMPHIICs4Fr6DCvqKOT7In" + "hxORZe+6kfkPiqWBSlA61OsEqMfdIs4oJgQwBKjH3SLOKCaLObVUFvBEfC+3feEH" + "3NKmLogOpT7rYtV8tDkCldvJlDq3hpb6UEwRBGEEHRxk8GjPRf+ipjqBt8E/a4hH" + "o+d+8U/j23/K/gy9EOjoJuA0NtZGqu+HsuJH1K8eir4ddSD5wqRcseuOlc/VUmK3" + "Cyn+7Fhk4ZwFT/mRKSgORkYhd5GBEUKCA0EmPFMVAjEAjLkegqM4bSgPXW9+UOZB" + "3xUvcQntVFazHxZubKwEJafPOrava3/DEDuIMgLpBGVlAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "brainpool512r1") + return + "-----BEGIN EC PARAMETERS-----" + "MIIBogIBATBMBgcqhkjOPQEBAkEAqt2duNvpxIs/1OauM8n8B8swjbOzydIO1mOc" + "ynAzCHF9TZsAm8ZoQq7NoSrmo4DmKIH/Ly2CxoUoqmBWWDpI8zCBhARAeDCjMYtg" + "O4niMnFFrCNMxZTL3Y09+RYQqDRByuqYY7wt7V1aqCU6oQou8cmLmsi1fxEXpyvy" + "x7nnwaxNd/yUygRAPfkWEKg0QcrqmGO8Le1dWqglOqEKLvHJi5rItX8RF6cr8se5" + "58GsTXf8lMrcCD5nmEBQt1665d0oCb1jgBb3IwSBgQSBruS92C7ZZFohMi6cTGqT" + "he2fcLXZFsG0O2Lu9NAJjv87H3ji0NSNUNFoe5O5fV98bVBHQGpeaIs1Igm8ufgi" + "fd44XVZjMuzA6r+pz3gi/fIJ9wAkpXsaoADFW4gfgRGy3N5JSl9IXlvKS9iKJ2Ou" + "0corL6jwVAZ4zR4POtgIkgJBAKrdnbjb6cSLP9TmrjPJ/AfLMI2zs8nSDtZjnMpw" + "MwhwVT5cQUypJhlBhmEZf6wQRx2x04EIXdrdtYeWgpypAGkCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "x962_p192v2") + return + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY" + "/////////////////////v/////////8BBjMItbfuVxrJeScDWNkpOWYDDk6ohZo" + "2VMEMQTuorrn4Ul4QvLed2nP6cmJwHKtaW9IA0pldNEdabbsemcruCoIPfLysIR9" + "6XCy3hUCGQD///////////////5fsack3IBBhkjY3TECAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "x962_p192v3") + return + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY" + "/////////////////////v/////////8BBgiEj3COVoFyqdCPa7MyUdgp9RiJWvV" + "aRYEMQR9KXeBAMZaHaF4NxZYjc4ri0rujiKPGJY4qQ8iY3M3M0tJ3LZqbcj5l4rK" + "dkipQ7ACGQD///////////////96YtAxyD9ClPZA7BMCAQE=" + "-----END EC PARAMETERS-----"; + + if(name == "x962_p239v1") + return + "-----BEGIN EC PARAMETERS-----" + "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////" + "/zBABB5///////////////9///////+AAAAAAAB///////wEHmsBbDvc8YlB0NZU" + "khR1ynGp2y+yfR03eWGFwpQsCgQ9BA/6ljzcqIFszDO4ZCvt+QXD01hXPT8n+707" + "PLmqr33r6OTpCl2ubkBUylMLoEZUs2gYziJrOfzLewLxrgIef///////////////" + "f///nl6an12QcfvRUiaIkJ0LAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "x962_p239v2") + return + "-----BEGIN EC PARAMETERS-----" + "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////" + "/zBABB5///////////////9///////+AAAAAAAB///////wEHmF/q2gyV2y7/tUN" + "mfAknD/uWLlLoAOMeuhMjIMvLAQ9BDivCdmHJ3BRIMkhu16eJilqPNzy81dXoOr9" + "h7gw51sBJeTb6g7HIG2g/AHZsIEyn7VV3m70YCN9/4vkugIef///////////////" + "gAAAz6foWUN31BTAOCG8WCBjAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "x962_p239v3") + return + "-----BEGIN EC PARAMETERS-----" + "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////" + "/zBABB5///////////////9///////+AAAAAAAB///////wEHiVXBfoqMGZUsfTL" + "A9anUKMMJQEC1JiHF9m6FattPgQ9BGdoro4Yu5LPzwBclJqixtlIU9DmYLv4VLHJ" + "UF/pWhYH5omPOQwGvB1VK60ibztvz+SLboGEma8Y4+1s8wIef///////////////" + "f///l13rQbOmBXw8QyFGUmVRAgEB" + "-----END EC PARAMETERS-----"; + + if(name == "gost_256A") + return + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQD/////////////////////////////////////" + "///9lzBEBCD////////////////////////////////////////9lAQgAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKYEQQQAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAY2R5HHgmJzaJ99QWkU/K3Y1KU8t3yPjsSKsyZyenx4UAiEA" + "/////////////////////2xhEHCZWtEARYQbCbdhuJMCAQE=" + "-----END EC PARAMETERS-----"; + + return nullptr; + } + +} diff --git a/src/lib/pubkey/ecc_key/ecc_key.cpp b/src/lib/pubkey/ecc_key/ecc_key.cpp new file mode 100644 index 000000000..c9d4d62fe --- /dev/null +++ b/src/lib/pubkey/ecc_key/ecc_key.cpp @@ -0,0 +1,148 @@ +/* +* ECC Key implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +size_t EC_PublicKey::estimated_strength() const + { + return domain().get_curve().get_p().bits() / 2; + } + +EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point) : + domain_params(dom_par), public_key(pub_point), + domain_encoding(EC_DOMPAR_ENC_EXPLICIT) + { + if(domain().get_curve() != public_point().get_curve()) + throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); + } + +EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) + { + domain_params = EC_Group(alg_id.parameters); + domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + public_key = OS2ECP(key_bits, domain().get_curve()); + } + +bool EC_PublicKey::check_key(RandomNumberGenerator&, + bool) const + { + return public_point().on_the_curve(); + } + +AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), DER_domain()); + } + +std::vector EC_PublicKey::x509_subject_public_key() const + { + return unlock(EC2OSP(public_point(), PointGFp::COMPRESSED)); + } + +void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) + { + if(form != EC_DOMPAR_ENC_EXPLICIT && + form != EC_DOMPAR_ENC_IMPLICITCA && + form != EC_DOMPAR_ENC_OID) + throw Invalid_Argument("Invalid encoding form for EC-key object specified"); + + if((form == EC_DOMPAR_ENC_OID) && (domain_params.get_oid() == "")) + throw Invalid_Argument("Invalid encoding form OID specified for " + "EC-key object whose corresponding domain " + "parameters are without oid"); + + domain_encoding = form; + } + +const BigInt& EC_PrivateKey::private_value() const + { + if(private_key == 0) + throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); + + return private_key; + } + +/** +* EC_PrivateKey constructor +*/ +EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& ec_group, + const BigInt& x) + { + domain_params = ec_group; + domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + if(x == 0) + private_key = BigInt::random_integer(rng, 1, domain().get_order()); + else + private_key = x; + + public_key = domain().get_base_point() * private_key; + + BOTAN_ASSERT(public_key.on_the_curve(), + "Generated public key point was on the curve"); + } + +secure_vector EC_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(1)) + .encode(BigInt::encode_1363(private_key, private_key.bytes()), + OCTET_STRING) + .end_cons() + .get_contents(); + } + +EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) + { + domain_params = EC_Group(alg_id.parameters); + domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + OID key_parameters; + secure_vector public_key_bits; + + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check(1, "Unknown version code for ECC key") + .decode_octet_string_bigint(private_key) + .decode_optional(key_parameters, ASN1_Tag(0), PRIVATE) + .decode_optional_string(public_key_bits, BIT_STRING, 1, PRIVATE) + .end_cons(); + + if(!key_parameters.empty() && key_parameters != alg_id.oid) + throw Decoding_Error("EC_PrivateKey - inner and outer OIDs did not match"); + + if(public_key_bits.empty()) + { + public_key = domain().get_base_point() * private_key; + + BOTAN_ASSERT(public_key.on_the_curve(), + "Public point derived from loaded key was on the curve"); + } + else + { + public_key = OS2ECP(public_key_bits, domain().get_curve()); + // OS2ECP verifies that the point is on the curve + } + } + +} diff --git a/src/lib/pubkey/ecc_key/ecc_key.h b/src/lib/pubkey/ecc_key/ecc_key.h new file mode 100644 index 000000000..de980608a --- /dev/null +++ b/src/lib/pubkey/ecc_key/ecc_key.h @@ -0,0 +1,121 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECC_PUBLIC_KEY_BASE_H__ +#define BOTAN_ECC_PUBLIC_KEY_BASE_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents abstract ECC public keys. When encoding a key +* via an encoder that can be accessed via the corresponding member +* functions, the key will decide upon its internally stored encoding +* information whether to encode itself with or without domain +* parameters, or using the domain parameter oid. Furthermore, a public +* key without domain parameters can be decoded. In that case, it +* cannot be used for verification until its domain parameters are set +* by calling the corresponding member function. +*/ +class BOTAN_DLL EC_PublicKey : public virtual Public_Key + { + public: + EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point); + + EC_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Get the public point of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the public point of this key + */ + const PointGFp& public_point() const { return public_key; } + + AlgorithmIdentifier algorithm_identifier() const; + + std::vector x509_subject_public_key() const; + + bool check_key(RandomNumberGenerator& rng, + bool strong) const; + + /** + * Get the domain parameters of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the domain parameters of this key + */ + const EC_Group& domain() const { return domain_params; } + + /** + * Set the domain parameter encoding to be used when encoding this key. + * @param enc the encoding to use + */ + void set_parameter_encoding(EC_Group_Encoding enc); + + /** + * Return the DER encoding of this keys domain in whatever format + * is preset for this particular key + */ + std::vector DER_domain() const + { return domain().DER_encode(domain_format()); } + + /** + * Get the domain parameter encoding to be used when encoding this key. + * @result the encoding to use + */ + EC_Group_Encoding domain_format() const + { return domain_encoding; } + + size_t estimated_strength() const override; + + protected: + EC_PublicKey() : domain_encoding(EC_DOMPAR_ENC_EXPLICIT) {} + + EC_Group domain_params; + PointGFp public_key; + EC_Group_Encoding domain_encoding; + }; + +/** +* This abstract class represents ECC private keys +*/ +class BOTAN_DLL EC_PrivateKey : public virtual EC_PublicKey, + public virtual Private_Key + { + public: + EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& private_key); + + EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + secure_vector pkcs8_private_key() const; + + /** + * Get the private key value of this key object. + * @result the private key value of this key object + */ + const BigInt& private_value() const; + protected: + EC_PrivateKey() {} + + BigInt private_key; + }; + +} + +#endif diff --git a/src/lib/pubkey/ecc_key/info.txt b/src/lib/pubkey/ecc_key/info.txt new file mode 100644 index 000000000..6d6d5f0e9 --- /dev/null +++ b/src/lib/pubkey/ecc_key/info.txt @@ -0,0 +1,10 @@ +define ECC_PUBLIC_KEY_CRYPTO 20131128 + + +alloc +asn1 +bigint +ec_gfp +ec_group +numbertheory + diff --git a/src/lib/pubkey/ecdh/ecdh.cpp b/src/lib/pubkey/ecdh/ecdh.cpp new file mode 100644 index 000000000..0f93a0f97 --- /dev/null +++ b/src/lib/pubkey/ecdh/ecdh.cpp @@ -0,0 +1,35 @@ +/* +* ECDH implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +ECDH_KA_Operation::ECDH_KA_Operation(const ECDH_PrivateKey& key) : + curve(key.domain().get_curve()), + cofactor(key.domain().get_cofactor()) + { + l_times_priv = inverse_mod(cofactor, key.domain().get_order()) * + key.private_value(); + } + +secure_vector ECDH_KA_Operation::agree(const byte w[], size_t w_len) + { + PointGFp point = OS2ECP(w, w_len, curve); + + PointGFp S = (cofactor * point) * l_times_priv; + + BOTAN_ASSERT(S.on_the_curve(), + "ECDH agreed value was on the curve"); + + return BigInt::encode_1363(S.get_affine_x(), + curve.get_p().bytes()); + } + +} diff --git a/src/lib/pubkey/ecdh/ecdh.h b/src/lib/pubkey/ecdh/ecdh.h new file mode 100644 index 000000000..0c5d4e010 --- /dev/null +++ b/src/lib/pubkey/ecdh/ecdh.h @@ -0,0 +1,107 @@ +/* +* ECDH +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECDH_KEY_H__ +#define BOTAN_ECDH_KEY_H__ + +#include +#include + +namespace Botan { + +/** +* This class represents ECDH Public Keys. +*/ +class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey + { + public: + + ECDH_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDH_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Get this keys algorithm name. + * @return this keys algorithm name + */ + std::string algo_name() const { return "ECDH"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + + * @return maximum number of input bits + */ + size_t max_input_bits() const { return domain().get_order().bits(); } + + /** + * @return public point value + */ + std::vector public_value() const + { return unlock(EC2OSP(public_point(), PointGFp::UNCOMPRESSED)); } + + protected: + ECDH_PublicKey() {} + }; + +/** +* This class represents ECDH Private Keys. +*/ +class BOTAN_DLL ECDH_PrivateKey : public ECDH_PublicKey, + public EC_PrivateKey, + public PK_Key_Agreement_Key + { + public: + + ECDH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + ECDH_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + std::vector public_value() const + { return ECDH_PublicKey::public_value(); } + }; + +/** +* ECDH operation +*/ +class BOTAN_DLL ECDH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + ECDH_KA_Operation(const ECDH_PrivateKey& key); + + secure_vector agree(const byte w[], size_t w_len); + private: + const CurveGFp& curve; + const BigInt& cofactor; + BigInt l_times_priv; + }; + +} + +#endif diff --git a/src/lib/pubkey/ecdh/info.txt b/src/lib/pubkey/ecdh/info.txt new file mode 100644 index 000000000..9277aca9b --- /dev/null +++ b/src/lib/pubkey/ecdh/info.txt @@ -0,0 +1,10 @@ +define ECDH 20131128 + + +alloc +asn1 +ec_group +ecc_key +libstate +numbertheory + diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp new file mode 100644 index 000000000..6ff082649 --- /dev/null +++ b/src/lib/pubkey/ecdsa/ecdsa.cpp @@ -0,0 +1,97 @@ +/* +* ECDSA implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +ECDSA_Signature_Operation::ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa) : + base_point(ecdsa.domain().get_base_point()), + order(ecdsa.domain().get_order()), + x(ecdsa.private_value()), + mod_order(order) + { + } + +secure_vector +ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + BigInt m(msg, msg_len); + + BigInt r = 0, s = 0; + + while(r == 0 || s == 0) + { + // This contortion is necessary for the tests + BigInt k; + k.randomize(rng, order.bits()); + + while(k >= order) + k.randomize(rng, order.bits() - 1); + + PointGFp k_times_P = base_point * k; + r = mod_order.reduce(k_times_P.get_affine_x()); + s = mod_order.multiply(inverse_mod(k, order), mul_add(x, r, m)); + } + + secure_vector output(2*order.bytes()); + r.binary_encode(&output[output.size() / 2 - r.bytes()]); + s.binary_encode(&output[output.size() - s.bytes()]); + return output; + } + +ECDSA_Verification_Operation::ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa) : + base_point(ecdsa.domain().get_base_point()), + public_point(ecdsa.public_point()), + order(ecdsa.domain().get_order()) + { + } + +bool ECDSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + if(sig_len != order.bytes()*2) + return false; + + BigInt e(msg, msg_len); + + BigInt r(sig, sig_len / 2); + BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= order || s <= 0 || s >= order) + return false; + + BigInt w = inverse_mod(s, order); + + PointGFp R = w * multi_exponentiate(base_point, e, + public_point, r); + + if(R.is_zero()) + return false; + + return (R.get_affine_x() % order == r); + } + +} diff --git a/src/lib/pubkey/ecdsa/ecdsa.h b/src/lib/pubkey/ecdsa/ecdsa.h new file mode 100644 index 000000000..e37fa1562 --- /dev/null +++ b/src/lib/pubkey/ecdsa/ecdsa.h @@ -0,0 +1,138 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECDSA_KEY_H__ +#define BOTAN_ECDSA_KEY_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents ECDSA Public Keys. +*/ +class BOTAN_DLL ECDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + ECDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECDSA") + */ + std::string algo_name() const { return "ECDSA"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + * @result the maximum number of input bits + */ + size_t max_input_bits() const { return domain().get_order().bits(); } + + size_t message_parts() const { return 2; } + + size_t message_part_size() const + { return domain().get_order().bytes(); } + + protected: + ECDSA_PublicKey() {} + }; + +/** +* This class represents ECDSA Private Keys +*/ +class BOTAN_DLL ECDSA_PrivateKey : public ECDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + ECDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a ney random key) + */ + ECDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + bool check_key(RandomNumberGenerator& rng, bool) const; + }; + +/** +* ECDSA signature operation +*/ +class BOTAN_DLL ECDSA_Signature_Operation : public PK_Ops::Signature + { + public: + ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa); + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + private: + const PointGFp& base_point; + const BigInt& order; + const BigInt& x; + Modular_Reducer mod_order; + }; + +/** +* ECDSA verification operation +*/ +class BOTAN_DLL ECDSA_Verification_Operation : public PK_Ops::Verification + { + public: + ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const PointGFp& base_point; + const PointGFp& public_point; + const BigInt& order; + }; + +} + +#endif diff --git a/src/lib/pubkey/ecdsa/info.txt b/src/lib/pubkey/ecdsa/info.txt new file mode 100644 index 000000000..fcf688402 --- /dev/null +++ b/src/lib/pubkey/ecdsa/info.txt @@ -0,0 +1,9 @@ +define ECDSA 20131128 + + +asn1 +ec_group +ecc_key +numbertheory +rng + diff --git a/src/lib/pubkey/elgamal/elgamal.cpp b/src/lib/pubkey/elgamal/elgamal.cpp new file mode 100644 index 000000000..c8a9ba9d0 --- /dev/null +++ b/src/lib/pubkey/elgamal/elgamal.cpp @@ -0,0 +1,135 @@ +/* +* ElGamal +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* ElGamal_PublicKey Constructor +*/ +ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* ElGamal_PrivateKey Constructor +*/ +ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + x.randomize(rng, 2 * dl_work_factor(group_p().bits())); + + y = power_mod(group_g(), x, group_p()); + + if(x_arg == 0) + gen_check(rng); + else + load_check(rng); + } + +ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + y = power_mod(group_g(), x, group_p()); + load_check(rng); + } + +/* +* Check Private ElGamal Parameters +*/ +bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + return KeyPair::encryption_consistency_check(rng, *this, "EME1(SHA-1)"); + } + +ElGamal_Encryption_Operation::ElGamal_Encryption_Operation(const ElGamal_PublicKey& key) + { + const BigInt& p = key.group_p(); + + powermod_g_p = Fixed_Base_Power_Mod(key.group_g(), p); + powermod_y_p = Fixed_Base_Power_Mod(key.get_y(), p); + mod_p = Modular_Reducer(p); + } + +secure_vector +ElGamal_Encryption_Operation::encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt& p = mod_p.get_modulus(); + + BigInt m(msg, msg_len); + + if(m >= p) + throw Invalid_Argument("ElGamal encryption: Input is too large"); + + BigInt k(rng, 2 * dl_work_factor(p.bits())); + + BigInt a = powermod_g_p(k); + BigInt b = mod_p.multiply(m, powermod_y_p(k)); + + secure_vector output(2*p.bytes()); + a.binary_encode(&output[p.bytes() - a.bytes()]); + b.binary_encode(&output[output.size() / 2 + (p.bytes() - b.bytes())]); + return output; + } + +ElGamal_Decryption_Operation::ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, + RandomNumberGenerator& rng) + { + const BigInt& p = key.group_p(); + + powermod_x_p = Fixed_Exponent_Power_Mod(key.get_x(), p); + mod_p = Modular_Reducer(p); + + BigInt k(rng, p.bits() - 1); + blinder = Blinder(k, powermod_x_p(k), p); + } + +secure_vector +ElGamal_Decryption_Operation::decrypt(const byte msg[], size_t msg_len) + { + const BigInt& p = mod_p.get_modulus(); + + const size_t p_bytes = p.bytes(); + + if(msg_len != 2 * p_bytes) + throw Invalid_Argument("ElGamal decryption: Invalid message"); + + BigInt a(msg, p_bytes); + BigInt b(msg + p_bytes, p_bytes); + + if(a >= p || b >= p) + throw Invalid_Argument("ElGamal decryption: Invalid message"); + + a = blinder.blind(a); + + BigInt r = mod_p.multiply(b, inverse_mod(powermod_x_p(a), p)); + + return BigInt::encode_locked(blinder.unblind(r)); + } + +} diff --git a/src/lib/pubkey/elgamal/elgamal.h b/src/lib/pubkey/elgamal/elgamal.h new file mode 100644 index 000000000..9566bcca6 --- /dev/null +++ b/src/lib/pubkey/elgamal/elgamal.h @@ -0,0 +1,96 @@ +/* +* ElGamal +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ELGAMAL_H__ +#define BOTAN_ELGAMAL_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* ElGamal Public Key +*/ +class BOTAN_DLL ElGamal_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "ElGamal"; } + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + + size_t max_input_bits() const { return (group_p().bits() - 1); } + + ElGamal_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + {} + + ElGamal_PublicKey(const DL_Group& group, const BigInt& y); + protected: + ElGamal_PublicKey() {} + }; + +/** +* ElGamal Private Key +*/ +class BOTAN_DLL ElGamal_PrivateKey : public ElGamal_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng); + + ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& priv_key = 0); + }; + +/** +* ElGamal encryption operation +*/ +class BOTAN_DLL ElGamal_Encryption_Operation : public PK_Ops::Encryption + { + public: + size_t max_input_bits() const { return mod_p.get_modulus().bits() - 1; } + + ElGamal_Encryption_Operation(const ElGamal_PublicKey& key); + + secure_vector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + private: + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p; + }; + +/** +* ElGamal decryption operation +*/ +class BOTAN_DLL ElGamal_Decryption_Operation : public PK_Ops::Decryption + { + public: + size_t max_input_bits() const { return mod_p.get_modulus().bits() - 1; } + + ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, + RandomNumberGenerator& rng); + + secure_vector decrypt(const byte msg[], size_t msg_len); + private: + Fixed_Exponent_Power_Mod powermod_x_p; + Modular_Reducer mod_p; + Blinder blinder; + }; + +} + +#endif diff --git a/src/lib/pubkey/elgamal/info.txt b/src/lib/pubkey/elgamal/info.txt new file mode 100644 index 000000000..4fe20e828 --- /dev/null +++ b/src/lib/pubkey/elgamal/info.txt @@ -0,0 +1,9 @@ +define ELGAMAL 20131128 + + +dl_algo +dl_group +keypair +libstate +numbertheory + diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp new file mode 100644 index 000000000..9a1e6d85b --- /dev/null +++ b/src/lib/pubkey/gost_3410/gost_3410.cpp @@ -0,0 +1,176 @@ +/* +* GOST 34.10-2001 implemenation +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +std::vector GOST_3410_PublicKey::x509_subject_public_key() const + { + // Trust CryptoPro to come up with something obnoxious + const BigInt x = public_point().get_affine_x(); + const BigInt y = public_point().get_affine_y(); + + size_t part_size = std::max(x.bytes(), y.bytes()); + + std::vector bits(2*part_size); + + x.binary_encode(&bits[part_size - x.bytes()]); + y.binary_encode(&bits[2*part_size - y.bytes()]); + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + return DER_Encoder().encode(bits, OCTET_STRING).get_contents_unlocked(); + } + +AlgorithmIdentifier GOST_3410_PublicKey::algorithm_identifier() const + { + std::vector params = + DER_Encoder().start_cons(SEQUENCE) + .encode(OID(domain().get_oid())) + .end_cons() + .get_contents_unlocked(); + + return AlgorithmIdentifier(get_oid(), params); + } + +GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) + { + OID ecc_param_id; + + // Also includes hash and cipher OIDs... brilliant design guys + BER_Decoder(alg_id.parameters).start_cons(SEQUENCE).decode(ecc_param_id); + + domain_params = EC_Group(ecc_param_id); + + secure_vector bits; + BER_Decoder(key_bits).decode(bits, OCTET_STRING); + + const size_t part_size = bits.size() / 2; + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + BigInt x(&bits[0], part_size); + BigInt y(&bits[part_size], part_size); + + public_key = PointGFp(domain().get_curve(), x, y); + + BOTAN_ASSERT(public_key.on_the_curve(), + "Loaded GOST 34.10 public key is on the curve"); + } + +namespace { + +BigInt decode_le(const byte msg[], size_t msg_len) + { + secure_vector msg_le(msg, msg + msg_len); + + for(size_t i = 0; i != msg_le.size() / 2; ++i) + std::swap(msg_le[i], msg_le[msg_le.size()-1-i]); + + return BigInt(&msg_le[0], msg_le.size()); + } + +} + +GOST_3410_Signature_Operation::GOST_3410_Signature_Operation( + const GOST_3410_PrivateKey& gost_3410) : + + base_point(gost_3410.domain().get_base_point()), + order(gost_3410.domain().get_order()), + x(gost_3410.private_value()) + { + } + +secure_vector +GOST_3410_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + BigInt k; + do + k.randomize(rng, order.bits()-1); + while(k >= order); + + BigInt e = decode_le(msg, msg_len); + + e %= order; + if(e == 0) + e = 1; + + PointGFp k_times_P = base_point * k; + + BOTAN_ASSERT(k_times_P.on_the_curve(), + "GOST 34.10 k*g is on the curve"); + + BigInt r = k_times_P.get_affine_x() % order; + + BigInt s = (r*x + k*e) % order; + + if(r == 0 || s == 0) + throw Invalid_State("GOST 34.10: r == 0 || s == 0"); + + secure_vector output(2*order.bytes()); + s.binary_encode(&output[output.size() / 2 - s.bytes()]); + r.binary_encode(&output[output.size() - r.bytes()]); + return output; + } + +GOST_3410_Verification_Operation::GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost) : + base_point(gost.domain().get_base_point()), + public_point(gost.public_point()), + order(gost.domain().get_order()) + { + } + +bool GOST_3410_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + if(sig_len != order.bytes()*2) + return false; + + BigInt e = decode_le(msg, msg_len); + + BigInt s(sig, sig_len / 2); + BigInt r(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= order || s <= 0 || s >= order) + return false; + + e %= order; + if(e == 0) + e = 1; + + BigInt v = inverse_mod(e, order); + + BigInt z1 = (s*v) % order; + BigInt z2 = (-r*v) % order; + + PointGFp R = multi_exponentiate(base_point, z1, + public_point, z2); + + if(R.is_zero()) + return false; + + return (R.get_affine_x() == r); + } + +} diff --git a/src/lib/pubkey/gost_3410/gost_3410.h b/src/lib/pubkey/gost_3410/gost_3410.h new file mode 100644 index 000000000..6b1506b10 --- /dev/null +++ b/src/lib/pubkey/gost_3410/gost_3410.h @@ -0,0 +1,139 @@ +/* +* GOST 34.10-2001 +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GOST_3410_KEY_H__ +#define BOTAN_GOST_3410_KEY_H__ + +#include +#include + +namespace Botan { + +/** +* GOST-34.10 Public Key +*/ +class BOTAN_DLL GOST_3410_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + GOST_3410_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Construct from X.509 algorithm id and subject public key bits + */ + GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Get this keys algorithm name. + * @result this keys algorithm name + */ + std::string algo_name() const { return "GOST-34.10"; } + + AlgorithmIdentifier algorithm_identifier() const; + + std::vector x509_subject_public_key() const; + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + + * @result the maximum number of input bits + */ + size_t max_input_bits() const { return domain().get_order().bits(); } + + size_t message_parts() const { return 2; } + + size_t message_part_size() const + { return domain().get_order().bytes(); } + + protected: + GOST_3410_PublicKey() {} + }; + +/** +* GOST-34.10 Private Key +*/ +class BOTAN_DLL GOST_3410_PrivateKey : public GOST_3410_PublicKey, + public EC_PrivateKey + { + public: + + GOST_3410_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + GOST_3410_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + AlgorithmIdentifier pkcs8_algorithm_identifier() const + { return EC_PublicKey::algorithm_identifier(); } + }; + +/** +* GOST-34.10 signature operation +*/ +class BOTAN_DLL GOST_3410_Signature_Operation : public PK_Ops::Signature + { + public: + GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + private: + const PointGFp& base_point; + const BigInt& order; + const BigInt& x; + }; + +/** +* GOST-34.10 verification operation +*/ +class BOTAN_DLL GOST_3410_Verification_Operation : public PK_Ops::Verification + { + public: + GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const PointGFp& base_point; + const PointGFp& public_point; + const BigInt& order; + }; + +} + +#endif diff --git a/src/lib/pubkey/gost_3410/info.txt b/src/lib/pubkey/gost_3410/info.txt new file mode 100644 index 000000000..63521d3dd --- /dev/null +++ b/src/lib/pubkey/gost_3410/info.txt @@ -0,0 +1,13 @@ +define GOST_34_10_2001 20131128 + +load_on auto + + +alloc +asn1 +ec_group +ecc_key +libstate +numbertheory +rng + diff --git a/src/lib/pubkey/if_algo/if_algo.cpp b/src/lib/pubkey/if_algo/if_algo.cpp new file mode 100644 index 000000000..f6aeb69db --- /dev/null +++ b/src/lib/pubkey/if_algo/if_algo.cpp @@ -0,0 +1,143 @@ +/* +* IF Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +size_t IF_Scheme_PublicKey::estimated_strength() const + { + return dl_work_factor(n.bits()); + } + +AlgorithmIdentifier IF_Scheme_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + AlgorithmIdentifier::USE_NULL_PARAM); + } + +std::vector IF_Scheme_PublicKey::x509_subject_public_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(n) + .encode(e) + .end_cons() + .get_contents_unlocked(); + } + +IF_Scheme_PublicKey::IF_Scheme_PublicKey(const AlgorithmIdentifier&, + const secure_vector& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode(n) + .decode(e) + .verify_end() + .end_cons(); + } + +/* +* Check IF Scheme Public Parameters +*/ +bool IF_Scheme_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + if(n < 35 || n.is_even() || e < 2) + return false; + return true; + } + +secure_vector IF_Scheme_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(0)) + .encode(n) + .encode(e) + .encode(d) + .encode(p) + .encode(q) + .encode(d1) + .encode(d2) + .encode(c) + .end_cons() + .get_contents(); + } + +IF_Scheme_PrivateKey::IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const AlgorithmIdentifier&, + const secure_vector& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check(0, "Unknown PKCS #1 key format version") + .decode(n) + .decode(e) + .decode(d) + .decode(p) + .decode(q) + .decode(d1) + .decode(d2) + .decode(c) + .end_cons(); + + load_check(rng); + } + +IF_Scheme_PrivateKey::IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const BigInt& prime1, + const BigInt& prime2, + const BigInt& exp, + const BigInt& d_exp, + const BigInt& mod) + { + p = prime1; + q = prime2; + e = exp; + d = d_exp; + n = mod.is_nonzero() ? mod : p * q; + + if(d == 0) + { + BigInt inv_for_d = lcm(p - 1, q - 1); + if(e.is_even()) + inv_for_d >>= 1; + + d = inverse_mod(e, inv_for_d); + } + + d1 = d % (p - 1); + d2 = d % (q - 1); + c = inverse_mod(q, p); + + load_check(rng); + } + +/* +* Check IF Scheme Private Parameters +*/ +bool IF_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(n < 35 || n.is_even() || e < 2 || d < 2 || p < 3 || q < 3 || p*q != n) + return false; + + if(!strong) + return true; + + if(d1 != d % (p - 1) || d2 != d % (q - 1) || c != inverse_mod(q, p)) + return false; + if(!check_prime(p, rng) || !check_prime(q, rng)) + return false; + return true; + } + +} diff --git a/src/lib/pubkey/if_algo/if_algo.h b/src/lib/pubkey/if_algo/if_algo.h new file mode 100644 index 000000000..7dd6d19f0 --- /dev/null +++ b/src/lib/pubkey/if_algo/if_algo.h @@ -0,0 +1,108 @@ +/* +* IF Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_IF_ALGO_H__ +#define BOTAN_IF_ALGO_H__ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents public keys +* of integer factorization based (IF) public key schemes. +*/ +class BOTAN_DLL IF_Scheme_PublicKey : public virtual Public_Key + { + public: + IF_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + IF_Scheme_PublicKey(const BigInt& n, const BigInt& e) : + n(n), e(e) {} + + bool check_key(RandomNumberGenerator& rng, bool) const; + + AlgorithmIdentifier algorithm_identifier() const; + + std::vector x509_subject_public_key() const; + + /** + * @return public modulus + */ + const BigInt& get_n() const { return n; } + + /** + * @return public exponent + */ + const BigInt& get_e() const { return e; } + + size_t max_input_bits() const { return (n.bits() - 1); } + + size_t estimated_strength() const override; + + protected: + IF_Scheme_PublicKey() {} + + BigInt n, e; + }; + +/** +* This class represents public keys +* of integer factorization based (IF) public key schemes. +*/ +class BOTAN_DLL IF_Scheme_PrivateKey : public virtual IF_Scheme_PublicKey, + public virtual Private_Key + { + public: + + IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const BigInt& prime1, const BigInt& prime2, + const BigInt& exp, const BigInt& d_exp, + const BigInt& mod); + + IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the first prime p. + * @return prime p + */ + const BigInt& get_p() const { return p; } + + /** + * Get the second prime q. + * @return prime q + */ + const BigInt& get_q() const { return q; } + + /** + * Get d with exp * d = 1 mod (p - 1, q - 1). + * @return d + */ + const BigInt& get_d() const { return d; } + + const BigInt& get_c() const { return c; } + const BigInt& get_d1() const { return d1; } + const BigInt& get_d2() const { return d2; } + + secure_vector pkcs8_private_key() const; + + protected: + IF_Scheme_PrivateKey() {} + + BigInt d, p, q, d1, d2, c; + }; + +} + +#endif diff --git a/src/lib/pubkey/if_algo/info.txt b/src/lib/pubkey/if_algo/info.txt new file mode 100644 index 000000000..e4d2dbb5e --- /dev/null +++ b/src/lib/pubkey/if_algo/info.txt @@ -0,0 +1,10 @@ +define IF_PUBLIC_KEY_FAMILY 20131128 + +load_on dep + + +asn1 +bigint +libstate +numbertheory + diff --git a/src/lib/pubkey/info.txt b/src/lib/pubkey/info.txt new file mode 100644 index 000000000..27a332b5c --- /dev/null +++ b/src/lib/pubkey/info.txt @@ -0,0 +1,41 @@ +define PUBLIC_KEY_CRYPTO 20131128 + + +blinding.cpp +pk_algs.cpp +pk_keys.cpp +pkcs8.cpp +pubkey.cpp +workfactor.cpp +x509_key.cpp + + + +blinding.h +pk_keys.h +pk_ops.h +pkcs8.h +pubkey.h +x509_key.h +workfactor.h + + + +pk_algs.h + + + +alloc +asn1 +bigint +engine +filters +kdf +libstate +oid_lookup +pbe +pem +pk_pad +rng +algo_base + diff --git a/src/lib/pubkey/keypair/info.txt b/src/lib/pubkey/keypair/info.txt new file mode 100644 index 000000000..10fb2013b --- /dev/null +++ b/src/lib/pubkey/keypair/info.txt @@ -0,0 +1,5 @@ +define KEYPAIR_TESTING 20131128 + + +libstate + diff --git a/src/lib/pubkey/keypair/keypair.cpp b/src/lib/pubkey/keypair/keypair.cpp new file mode 100644 index 000000000..a8631062d --- /dev/null +++ b/src/lib/pubkey/keypair/keypair.cpp @@ -0,0 +1,81 @@ +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace KeyPair { + +/* +* Check an encryption key pair for consistency +*/ +bool encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + PK_Encryptor_EME encryptor(key, padding); + PK_Decryptor_EME decryptor(key, padding); + + /* + Weird corner case, if the key is too small to encrypt anything at + all. This can happen with very small RSA keys with PSS + */ + if(encryptor.maximum_input_size() == 0) + return true; + + std::vector plaintext = + unlock(rng.random_vec(encryptor.maximum_input_size() - 1)); + + std::vector ciphertext = encryptor.encrypt(plaintext, rng); + if(ciphertext == plaintext) + return false; + + std::vector decrypted = unlock(decryptor.decrypt(ciphertext)); + + return (plaintext == decrypted); + } + +/* +* Check a signature key pair for consistency +*/ +bool signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + PK_Signer signer(key, padding); + PK_Verifier verifier(key, padding); + + std::vector message = unlock(rng.random_vec(16)); + + std::vector signature; + + try + { + signature = signer.sign_message(message, rng); + } + catch(Encoding_Error) + { + return false; + } + + if(!verifier.verify_message(message, signature)) + return false; + + // Now try to check a corrupt signature, ensure it does not succeed + ++message[0]; + + if(verifier.verify_message(message, signature)) + return false; + + return true; + } + +} + +} diff --git a/src/lib/pubkey/keypair/keypair.h b/src/lib/pubkey/keypair/keypair.h new file mode 100644 index 000000000..c7b128e53 --- /dev/null +++ b/src/lib/pubkey/keypair/keypair.h @@ -0,0 +1,47 @@ +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KEYPAIR_CHECKS_H__ +#define BOTAN_KEYPAIR_CHECKS_H__ + +#include + +namespace Botan { + +namespace KeyPair { + +/** +* Tests whether the key is consistent for encryption; whether +* encrypting and then decrypting gives to the original plaintext. +* @param rng the rng to use +* @param key the key to test +* @param padding the encryption padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_DLL bool +encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding); + +/** +* Tests whether the key is consistent for signatures; whether a +* signature can be created and then verified +* @param rng the rng to use +* @param key the key to test +* @param padding the signature padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_DLL bool +signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding); + +} + +} + +#endif diff --git a/src/lib/pubkey/nr/info.txt b/src/lib/pubkey/nr/info.txt new file mode 100644 index 000000000..8c2816fe7 --- /dev/null +++ b/src/lib/pubkey/nr/info.txt @@ -0,0 +1,9 @@ +define NYBERG_RUEPPEL 20131128 + + +dl_algo +dl_group +keypair +libstate +numbertheory + diff --git a/src/lib/pubkey/nr/nr.cpp b/src/lib/pubkey/nr/nr.cpp new file mode 100644 index 000000000..87cf3d038 --- /dev/null +++ b/src/lib/pubkey/nr/nr.cpp @@ -0,0 +1,143 @@ +/* +* Nyberg-Rueppel +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +NR_PublicKey::NR_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + } + +/* +* NR_PublicKey Constructor +*/ +NR_PublicKey::NR_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* Create a NR private key +*/ +NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + x = BigInt::random_integer(rng, 2, group_q() - 1); + + y = power_mod(group_g(), x, group_p()); + + if(x_arg == 0) + gen_check(rng); + else + load_check(rng); + } + +NR_PrivateKey::NR_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + y = power_mod(group_g(), x, group_p()); + + load_check(rng); + } + +/* +* Check Private Nyberg-Rueppel Parameters +*/ +bool NR_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +NR_Signature_Operation::NR_Signature_Operation(const NR_PrivateKey& nr) : + q(nr.group_q()), + x(nr.get_x()), + powermod_g_p(nr.group_g(), nr.group_p()), + mod_q(nr.group_q()) + { + } + +secure_vector +NR_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + BigInt f(msg, msg_len); + + if(f >= q) + throw Invalid_Argument("NR_Signature_Operation: Input is out of range"); + + BigInt c, d; + + while(c == 0) + { + BigInt k; + do + k.randomize(rng, q.bits()); + while(k >= q); + + c = mod_q.reduce(powermod_g_p(k) + f); + d = mod_q.reduce(k - x * c); + } + + secure_vector output(2*q.bytes()); + c.binary_encode(&output[output.size() / 2 - c.bytes()]); + d.binary_encode(&output[output.size() - d.bytes()]); + return output; + } + +NR_Verification_Operation::NR_Verification_Operation(const NR_PublicKey& nr) : + q(nr.group_q()), y(nr.get_y()) + { + powermod_g_p = Fixed_Base_Power_Mod(nr.group_g(), nr.group_p()); + powermod_y_p = Fixed_Base_Power_Mod(y, nr.group_p()); + mod_p = Modular_Reducer(nr.group_p()); + mod_q = Modular_Reducer(nr.group_q()); + } + +secure_vector +NR_Verification_Operation::verify_mr(const byte msg[], size_t msg_len) + { + const BigInt& q = mod_q.get_modulus(); + + if(msg_len != 2*q.bytes()) + throw Invalid_Argument("NR verification: Invalid signature"); + + BigInt c(msg, q.bytes()); + BigInt d(msg + q.bytes(), q.bytes()); + + if(c.is_zero() || c >= q || d >= q) + throw Invalid_Argument("NR verification: Invalid signature"); + + auto future_y_c = std::async(std::launch::async, powermod_y_p, c); + BigInt g_d = powermod_g_p(d); + + BigInt i = mod_p.multiply(g_d, future_y_c.get()); + return BigInt::encode_locked(mod_q.reduce(c - i)); + } + +} diff --git a/src/lib/pubkey/nr/nr.h b/src/lib/pubkey/nr/nr.h new file mode 100644 index 000000000..5be336a21 --- /dev/null +++ b/src/lib/pubkey/nr/nr.h @@ -0,0 +1,104 @@ +/* +* Nyberg-Rueppel +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NYBERG_RUEPPEL_H__ +#define BOTAN_NYBERG_RUEPPEL_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Nyberg-Rueppel Public Key +*/ +class BOTAN_DLL NR_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "NR"; } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_57; } + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return group_q().bytes(); } + size_t max_input_bits() const { return (group_q().bits() - 1); } + + NR_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + NR_PublicKey(const DL_Group& group, const BigInt& pub_key); + protected: + NR_PublicKey() {} + }; + +/** +* Nyberg-Rueppel Private Key +*/ +class BOTAN_DLL NR_PrivateKey : public NR_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool strong) const; + + NR_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng); + + NR_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& x = 0); + }; + +/** +* Nyberg-Rueppel signature operation +*/ +class BOTAN_DLL NR_Signature_Operation : public PK_Ops::Signature + { + public: + NR_Signature_Operation(const NR_PrivateKey& nr); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return (q.bits() - 1); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const BigInt& q; + const BigInt& x; + Fixed_Base_Power_Mod powermod_g_p; + Modular_Reducer mod_q; + }; + +/** +* Nyberg-Rueppel verification operation +*/ +class BOTAN_DLL NR_Verification_Operation : public PK_Ops::Verification + { + public: + NR_Verification_Operation(const NR_PublicKey& nr); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return (q.bits() - 1); } + + bool with_recovery() const { return true; } + + secure_vector verify_mr(const byte msg[], size_t msg_len); + private: + const BigInt& q; + const BigInt& y; + + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p, mod_q; + }; + +} + +#endif diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp new file mode 100644 index 000000000..9673199e0 --- /dev/null +++ b/src/lib/pubkey/pk_algs.cpp @@ -0,0 +1,160 @@ +/* +* PK Key +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#if defined(BOTAN_HAS_RSA) + #include +#endif + +#if defined(BOTAN_HAS_DSA) + #include +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + #include +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + #include +#endif + +#if defined(BOTAN_HAS_RW) + #include +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include +#endif + +#if defined(BOTAN_HAS_ECDH) + #include +#endif + +namespace Botan { + +Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) + { + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string()); + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return new RSA_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_RW) + if(alg_name == "RW") + return new RW_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return new DSA_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return new DH_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(alg_name == "NR") + return new NR_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return new ElGamal_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return new ECDSA_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return new GOST_3410_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return new ECDH_PublicKey(alg_id, key_bits); +#endif + + return nullptr; + } + +Private_Key* make_private_key(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) + { + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string()); + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return new RSA_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_RW) + if(alg_name == "RW") + return new RW_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return new DSA_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return new DH_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(alg_name == "NR") + return new NR_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return new ElGamal_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return new ECDSA_PrivateKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return new GOST_3410_PrivateKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return new ECDH_PrivateKey(alg_id, key_bits); +#endif + + return nullptr; + } + +} diff --git a/src/lib/pubkey/pk_algs.h b/src/lib/pubkey/pk_algs.h new file mode 100644 index 000000000..d8f24a1b8 --- /dev/null +++ b/src/lib/pubkey/pk_algs.h @@ -0,0 +1,24 @@ +/* +* PK Key Factory +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_KEY_FACTORY_H__ +#define BOTAN_PK_KEY_FACTORY_H__ + +#include + +namespace Botan { + +Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + +Private_Key* make_private_key(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng); + +} + +#endif diff --git a/src/lib/pubkey/pk_keys.cpp b/src/lib/pubkey/pk_keys.cpp new file mode 100644 index 000000000..c19c676ab --- /dev/null +++ b/src/lib/pubkey/pk_keys.cpp @@ -0,0 +1,55 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Default OID access +*/ +OID Public_Key::get_oid() const + { + try { + return OIDS::lookup(algo_name()); + } + catch(Lookup_Error) + { + throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs"); + } + } + +/* +* Run checks on a loaded public key +*/ +void Public_Key::load_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PUBLIC_KEY_STRONG_CHECKS_ON_LOAD)) + throw Invalid_Argument(algo_name() + ": Invalid public key"); + } + +/* +* Run checks on a loaded private key +*/ +void Private_Key::load_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD)) + throw Invalid_Argument(algo_name() + ": Invalid private key"); + } + +/* +* Run checks on a generated private key +*/ +void Private_Key::gen_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE)) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +} diff --git a/src/lib/pubkey/pk_keys.h b/src/lib/pubkey/pk_keys.h new file mode 100644 index 000000000..a8585c154 --- /dev/null +++ b/src/lib/pubkey/pk_keys.h @@ -0,0 +1,149 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_KEYS_H__ +#define BOTAN_PK_KEYS_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Public Key Base Class. +*/ +class BOTAN_DLL Public_Key + { + public: + /** + * Get the name of the underlying public key scheme. + * @return name of the public key scheme + */ + virtual std::string algo_name() const = 0; + + /** + * Return the estimated strength of the underlying key against + * the best currently known attack. Note that this ignores anything + * but pure attacks against the key itself and do not take into + * account padding schemes, usage mistakes, etc which might reduce + * the strength. However it does suffice to provide an upper bound. + * + * @return estimated strength in bits + */ + virtual size_t estimated_strength() const = 0; + + /** + * Get the OID of the underlying public key scheme. + * @return OID of the public key scheme + */ + virtual OID get_oid() const; + + /** + * Test the key values for consistency. + * @param rng rng to use + * @param strong whether to perform strong and lengthy version + * of the test + * @return true if the test is passed + */ + virtual bool check_key(RandomNumberGenerator& rng, + bool strong) const = 0; + + /** + * Find out the number of message parts supported by this scheme. + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return size of the message parts in bits + */ + virtual size_t message_part_size() const { return 0; } + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message size in bits + */ + virtual size_t max_input_bits() const = 0; + + /** + * @return X.509 AlgorithmIdentifier for this key + */ + virtual AlgorithmIdentifier algorithm_identifier() const = 0; + + /** + * @return X.509 subject key encoding for this key object + */ + virtual std::vector x509_subject_public_key() const = 0; + + virtual ~Public_Key() {} + protected: + /** + * Self-test after loading a key + * @param rng a random number generator + */ + virtual void load_check(RandomNumberGenerator& rng) const; + }; + +/** +* Private Key Base Class +*/ +class BOTAN_DLL Private_Key : public virtual Public_Key + { + public: + /** + * @return PKCS #8 private key encoding for this key object + */ + virtual secure_vector pkcs8_private_key() const = 0; + + /** + * @return PKCS #8 AlgorithmIdentifier for this key + * Might be different from the X.509 identifier, but normally is not + */ + virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const + { return algorithm_identifier(); } + + protected: + /** + * Self-test after loading a key + * @param rng a random number generator + */ + void load_check(RandomNumberGenerator& rng) const; + + /** + * Self-test after generating a key + * @param rng a random number generator + */ + void gen_check(RandomNumberGenerator& rng) const; + }; + +/** +* PK Secret Value Derivation Key +*/ +class BOTAN_DLL PK_Key_Agreement_Key : public virtual Private_Key + { + public: + /* + * @return public component of this key + */ + virtual std::vector public_value() const = 0; + + virtual ~PK_Key_Agreement_Key() {} + }; + +/* +* Typedefs +*/ +typedef PK_Key_Agreement_Key PK_KA_Key; +typedef Public_Key X509_PublicKey; +typedef Private_Key PKCS8_PrivateKey; + +} + +#endif diff --git a/src/lib/pubkey/pk_ops.h b/src/lib/pubkey/pk_ops.h new file mode 100644 index 000000000..8a08ef430 --- /dev/null +++ b/src/lib/pubkey/pk_ops.h @@ -0,0 +1,163 @@ +/* +* PK Operation Types +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_OPERATIONS_H__ +#define BOTAN_PK_OPERATIONS_H__ + +#include +#include + +namespace Botan { + +namespace PK_Ops { + +/** +* Public key encryption interface +*/ +class BOTAN_DLL Encryption + { + public: + virtual size_t max_input_bits() const = 0; + + virtual secure_vector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + virtual ~Encryption() {} + }; + +/** +* Public key decryption interface +*/ +class BOTAN_DLL Decryption + { + public: + virtual size_t max_input_bits() const = 0; + + virtual secure_vector decrypt(const byte msg[], + size_t msg_len) = 0; + + virtual ~Decryption() {} + }; + +/** +* Public key signature creation interface +*/ +class BOTAN_DLL Signature + { + public: + /** + * Find out the number of message parts supported by this scheme. + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return size of the message parts + */ + virtual size_t message_part_size() const { return 0; } + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + /* + * Perform a signature operation + * @param msg the message + * @param msg_len the length of msg in bytes + * @param rng a random number generator + */ + virtual secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + virtual ~Signature() {} + }; + +/** +* Public key signature verification interface +*/ +class BOTAN_DLL Verification + { + public: + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + /** + * Find out the number of message parts supported by this scheme. + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return size of the message parts + */ + virtual size_t message_part_size() const { return 0; } + + /** + * @return boolean specifying if this key type supports message + * recovery and thus if you need to call verify() or verify_mr() + */ + virtual bool with_recovery() const = 0; + + /* + * Perform a signature check operation + * @param msg the message + * @param msg_len the length of msg in bytes + * @param sig the signature + * @param sig_len the length of sig in bytes + * @returns if signature is a valid one for message + */ + virtual bool verify(const byte[], size_t, + const byte[], size_t) + { + throw Invalid_State("Message recovery required"); + } + + /* + * Perform a signature operation (with message recovery) + * Only call this if with_recovery() returns true + * @param msg the message + * @param msg_len the length of msg in bytes + * @returns recovered message + */ + virtual secure_vector verify_mr(const byte[], + size_t) + { + throw Invalid_State("Message recovery not supported"); + } + + virtual ~Verification() {} + }; + +/** +* A generic key agreement Operation (eg DH or ECDH) +*/ +class BOTAN_DLL Key_Agreement + { + public: + /* + * Perform a key agreement operation + * @param w the other key value + * @param w_len the length of w in bytes + * @returns the agreed key + */ + virtual secure_vector agree(const byte w[], size_t w_len) = 0; + + virtual ~Key_Agreement() {} + }; + +} + +} + +#endif diff --git a/src/lib/pubkey/pkcs8.cpp b/src/lib/pubkey/pkcs8.cpp new file mode 100644 index 000000000..0dd97a866 --- /dev/null +++ b/src/lib/pubkey/pkcs8.cpp @@ -0,0 +1,284 @@ +/* +* PKCS #8 +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace PKCS8 { + +namespace { + +/* +* Get info from an EncryptedPrivateKeyInfo +*/ +secure_vector PKCS8_extract(DataSource& source, + AlgorithmIdentifier& pbe_alg_id) + { + secure_vector key_data; + + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(pbe_alg_id) + .decode(key_data, OCTET_STRING) + .verify_end(); + + return key_data; + } + +/* +* PEM decode and/or decrypt a private key +*/ +secure_vector PKCS8_decode( + DataSource& source, + std::function ()> get_passphrase, + AlgorithmIdentifier& pk_alg_id) + { + AlgorithmIdentifier pbe_alg_id; + secure_vector key_data, key; + bool is_encrypted = true; + + try { + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + key_data = PKCS8_extract(source, pbe_alg_id); + else + { + std::string label; + key_data = PEM_Code::decode(source, label); + if(label == "PRIVATE KEY") + is_encrypted = false; + else if(label == "ENCRYPTED PRIVATE KEY") + { + DataSource_Memory key_source(key_data); + key_data = PKCS8_extract(key_source, pbe_alg_id); + } + else + throw PKCS8_Exception("Unknown PEM label " + label); + } + + if(key_data.empty()) + throw PKCS8_Exception("No key data found"); + } + catch(Decoding_Error& e) + { + throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what())); + } + + if(!is_encrypted) + key = key_data; + + const size_t MAX_TRIES = 3; + + size_t tries = 0; + while(true) + { + try { + if(MAX_TRIES && tries >= MAX_TRIES) + break; + + if(is_encrypted) + { + std::pair pass = get_passphrase(); + + if(pass.first == false) + break; + + Pipe decryptor(get_pbe(pbe_alg_id.oid, pbe_alg_id.parameters, pass.second)); + + decryptor.process_msg(key_data); + key = decryptor.read_all(); + } + + BER_Decoder(key) + .start_cons(SEQUENCE) + .decode_and_check(0, "Unknown PKCS #8 version number") + .decode(pk_alg_id) + .decode(key, OCTET_STRING) + .discard_remaining() + .end_cons(); + + break; + } + catch(Decoding_Error) + { + ++tries; + } + } + + if(key.empty()) + throw Decoding_Error("PKCS #8 private key decoding failed"); + return key; + } + +} + +/* +* BER encode a PKCS #8 private key, unencrypted +*/ +secure_vector BER_encode(const Private_Key& key) + { + const size_t PKCS8_VERSION = 0; + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(PKCS8_VERSION) + .encode(key.pkcs8_algorithm_identifier()) + .encode(key.pkcs8_private_key(), OCTET_STRING) + .end_cons() + .get_contents(); + } + +/* +* PEM encode a PKCS #8 private key, unencrypted +*/ +std::string PEM_encode(const Private_Key& key) + { + return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY"); + } + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec, + const std::string& pbe_algo) + { + const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,AES-256/CBC)"; + + std::unique_ptr pbe( + get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE), + pass, + msec, + rng)); + + AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params()); + + Pipe key_encrytor(pbe.release()); + key_encrytor.process_msg(PKCS8::BER_encode(key)); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(pbe_algid) + .encode(key_encrytor.read_all(), OCTET_STRING) + .end_cons() + .get_contents_unlocked(); + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec, + const std::string& pbe_algo) + { + if(pass == "") + return PEM_encode(key); + + return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo), + "ENCRYPTED PRIVATE KEY"); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + std::function ()> get_pass) + { + AlgorithmIdentifier alg_id; + secure_vector pkcs8_key = PKCS8_decode(source, get_pass, alg_id); + + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "" || alg_name == alg_id.oid.as_string()) + throw PKCS8_Exception("Unknown algorithm OID: " + + alg_id.oid.as_string()); + + return make_private_key(alg_id, pkcs8_key, rng); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + std::function ()> get_pass) + { + DataSource_Stream source(fsname, true); + return PKCS8::load_key(source, rng, get_pass); + } + +namespace { + +class Single_Shot_Passphrase + { + public: + Single_Shot_Passphrase(const std::string& pass) : + passphrase(pass), first(true) {} + + std::pair operator()() + { + if(first) + { + first = false; + return std::make_pair(true, passphrase); + } + else + return std::make_pair(false, ""); + } + + private: + std::string passphrase; + bool first; + }; + +} + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass) + { + return PKCS8::load_key(source, rng, Single_Shot_Passphrase(pass)); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const std::string& pass) + { + return PKCS8::load_key(fsname, rng, Single_Shot_Passphrase(pass)); + } + +/* +* Make a copy of this private key +*/ +Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng) + { + DataSource_Memory source(PEM_encode(key)); + return PKCS8::load_key(source, rng); + } + +} + +} diff --git a/src/lib/pubkey/pkcs8.h b/src/lib/pubkey/pkcs8.h new file mode 100644 index 000000000..302003ad4 --- /dev/null +++ b/src/lib/pubkey/pkcs8.h @@ -0,0 +1,141 @@ +/* +* PKCS #8 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PKCS8_H__ +#define BOTAN_PKCS8_H__ + +#include +#include +#include + +namespace Botan { + +/** +* PKCS #8 General Exception +*/ +struct BOTAN_DLL PKCS8_Exception : public Decoding_Error + { + PKCS8_Exception(const std::string& error) : + Decoding_Error("PKCS #8: " + error) {} + }; + +/** +* This namespace contains functions for handling PKCS #8 private keys +*/ +namespace PKCS8 { + +/** +* BER encode a private key +* @param key the private key to encode +* @return BER encoded key +*/ +BOTAN_DLL secure_vector BER_encode(const Private_Key& key); + +/** +* Get a string containing a PEM encoded private key. +* @param key the key to encode +* @return encoded key +*/ +BOTAN_DLL std::string PEM_encode(const Private_Key& key); + +/** +* Encrypt a key using PKCS #8 encryption +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param msec number of milliseconds to run the password derivation +* @param pbe_algo the name of the desired password-based encryption + algorithm; if empty ("") a reasonable (portable/secure) + default will be chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_DLL std::vector +BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec = std::chrono::milliseconds(300), + const std::string& pbe_algo = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param msec number of milliseconds to run the password derivation +* @param pbe_algo the name of the desired password-based encryption + algorithm; if empty ("") a reasonable (portable/secure) + default will be chosen. +* @return encrypted key in PEM form +*/ +BOTAN_DLL std::string +PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec = std::chrono::milliseconds(300), + const std::string& pbe_algo = ""); + +/** +* Load a key from a data source. +* @param source the data source providing the encoded key +* @param rng the rng to use +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key( + DataSource& source, + RandomNumberGenerator& rng, + std::function ()> get_passphrase); + +/** Load a key from a data source. +* @param source the data source providing the encoded key +* @param rng the rng to use +* @param pass the passphrase to decrypt the key. Provide an empty +* string if the key is not encrypted +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass = ""); + +/** +* Load a key from a file. +* @param filename the path to the file containing the encoded key +* @param rng the rng to use +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key( + const std::string& filename, + RandomNumberGenerator& rng, + std::function ()> get_passphrase); + +/** Load a key from a file. +* @param filename the path to the file containing the encoded key +* @param rng the rng to use +* @param pass the passphrase to decrypt the key. Provide an empty +* string if the key is not encrypted +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const std::string& pass = ""); + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @param rng the rng to use +* @return new copy of the key +*/ +BOTAN_DLL Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng); + +} + +} + +#endif diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp new file mode 100644 index 000000000..313d54c16 --- /dev/null +++ b/src/lib/pubkey/pubkey.cpp @@ -0,0 +1,386 @@ +/* +* Public Key Base +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* PK_Encryptor_EME Constructor +*/ +PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key, + const std::string& eme_name) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + RandomNumberGenerator& rng = global_state().global_rng(); + + while(const Engine* engine = i.next()) + { + op = engine->get_encryption_op(key, rng); + if(op) + break; + } + + if(!op) + throw Lookup_Error("Encryption with " + key.algo_name() + " not supported"); + + eme = (eme_name == "Raw") ? nullptr : get_eme(eme_name); + } + +/* +* Encrypt a message +*/ +std::vector +PK_Encryptor_EME::enc(const byte in[], + size_t length, + RandomNumberGenerator& rng) const + { + if(eme) + { + secure_vector encoded = + eme->encode(in, length, op->max_input_bits(), rng); + + if(8*(encoded.size() - 1) + high_bit(encoded[0]) > op->max_input_bits()) + throw Invalid_Argument("PK_Encryptor_EME: Input is too large"); + + return unlock(op->encrypt(&encoded[0], encoded.size(), rng)); + } + else + { + if(8*(length - 1) + high_bit(in[0]) > op->max_input_bits()) + throw Invalid_Argument("PK_Encryptor_EME: Input is too large"); + + return unlock(op->encrypt(&in[0], length, rng)); + } + } + +/* +* Return the max size, in bytes, of a message +*/ +size_t PK_Encryptor_EME::maximum_input_size() const + { + if(!eme) + return (op->max_input_bits() / 8); + else + return eme->maximum_input_size(op->max_input_bits()); + } + +/* +* PK_Decryptor_EME Constructor +*/ +PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key, + const std::string& eme_name) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + RandomNumberGenerator& rng = global_state().global_rng(); + + while(const Engine* engine = i.next()) + { + op = engine->get_decryption_op(key, rng); + if(op) + break; + } + + if(!op) + throw Lookup_Error("Decryption with " + key.algo_name() + " not supported"); + + eme = (eme_name == "Raw") ? nullptr : get_eme(eme_name); + } + +/* +* Decrypt a message +*/ +secure_vector PK_Decryptor_EME::dec(const byte msg[], + size_t length) const + { + try { + secure_vector decrypted = op->decrypt(msg, length); + if(eme) + return eme->decode(decrypted, op->max_input_bits()); + else + return decrypted; + } + catch(Invalid_Argument) + { + throw Decoding_Error("PK_Decryptor_EME: Input is invalid"); + } + } + +/* +* PK_Signer Constructor +*/ +PK_Signer::PK_Signer(const Private_Key& key, + const std::string& emsa_name, + Signature_Format format, + Fault_Protection prot) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + RandomNumberGenerator& rng = global_state().global_rng(); + + op = nullptr; + verify_op = nullptr; + + while(const Engine* engine = i.next()) + { + if(!op) + op = engine->get_signature_op(key, rng); + + if(!verify_op && prot == ENABLE_FAULT_PROTECTION) + verify_op = engine->get_verify_op(key, rng); + + if(op && (verify_op || prot == DISABLE_FAULT_PROTECTION)) + break; + } + + if(!op || (!verify_op && prot == ENABLE_FAULT_PROTECTION)) + throw Lookup_Error("Signing with " + key.algo_name() + " not supported"); + + emsa = get_emsa(emsa_name); + sig_format = format; + } + +/* +* Sign a message +*/ +std::vector PK_Signer::sign_message(const byte msg[], size_t length, + RandomNumberGenerator& rng) + { + update(msg, length); + return signature(rng); + } + +/* +* Add more to the message to be signed +*/ +void PK_Signer::update(const byte in[], size_t length) + { + emsa->update(in, length); + } + +/* +* Check the signature we just created, to help prevent fault attacks +*/ +bool PK_Signer::self_test_signature(const std::vector& msg, + const std::vector& sig) const + { + if(!verify_op) + return true; // checking disabled, assume ok + + if(verify_op->with_recovery()) + { + std::vector recovered = + unlock(verify_op->verify_mr(&sig[0], sig.size())); + + if(msg.size() > recovered.size()) + { + size_t extra_0s = msg.size() - recovered.size(); + + for(size_t i = 0; i != extra_0s; ++i) + if(msg[i] != 0) + return false; + + return same_mem(&msg[extra_0s], &recovered[0], recovered.size()); + } + + return (recovered == msg); + } + else + return verify_op->verify(&msg[0], msg.size(), + &sig[0], sig.size()); + } + +/* +* Create a signature +*/ +std::vector PK_Signer::signature(RandomNumberGenerator& rng) + { + std::vector encoded = unlock(emsa->encoding_of(emsa->raw_data(), + op->max_input_bits(), + rng)); + + std::vector plain_sig = unlock(op->sign(&encoded[0], encoded.size(), rng)); + + BOTAN_ASSERT(self_test_signature(encoded, plain_sig), "Signature was consistent"); + + if(op->message_parts() == 1 || sig_format == IEEE_1363) + return plain_sig; + + if(sig_format == DER_SEQUENCE) + { + if(plain_sig.size() % op->message_parts()) + throw Encoding_Error("PK_Signer: strange signature size found"); + const size_t SIZE_OF_PART = plain_sig.size() / op->message_parts(); + + std::vector sig_parts(op->message_parts()); + for(size_t j = 0; j != sig_parts.size(); ++j) + sig_parts[j].binary_decode(&plain_sig[SIZE_OF_PART*j], SIZE_OF_PART); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(sig_parts) + .end_cons() + .get_contents_unlocked(); + } + else + throw Encoding_Error("PK_Signer: Unknown signature format " + + std::to_string(sig_format)); + } + +/* +* PK_Verifier Constructor +*/ +PK_Verifier::PK_Verifier(const Public_Key& key, + const std::string& emsa_name, + Signature_Format format) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + RandomNumberGenerator& rng = global_state().global_rng(); + + while(const Engine* engine = i.next()) + { + op = engine->get_verify_op(key, rng); + if(op) + break; + } + + if(!op) + throw Lookup_Error("Verification with " + key.algo_name() + " not supported"); + + emsa = get_emsa(emsa_name); + sig_format = format; + } + +/* +* Set the signature format +*/ +void PK_Verifier::set_input_format(Signature_Format format) + { + if(op->message_parts() == 1 && format != IEEE_1363) + throw Invalid_State("PK_Verifier: This algorithm always uses IEEE 1363"); + sig_format = format; + } + +/* +* Verify a message +*/ +bool PK_Verifier::verify_message(const byte msg[], size_t msg_length, + const byte sig[], size_t sig_length) + { + update(msg, msg_length); + return check_signature(sig, sig_length); + } + +/* +* Append to the message +*/ +void PK_Verifier::update(const byte in[], size_t length) + { + emsa->update(in, length); + } + +/* +* Check a signature +*/ +bool PK_Verifier::check_signature(const byte sig[], size_t length) + { + try { + if(sig_format == IEEE_1363) + return validate_signature(emsa->raw_data(), sig, length); + else if(sig_format == DER_SEQUENCE) + { + BER_Decoder decoder(sig, length); + BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); + + size_t count = 0; + std::vector real_sig; + while(ber_sig.more_items()) + { + BigInt sig_part; + ber_sig.decode(sig_part); + real_sig += BigInt::encode_1363(sig_part, op->message_part_size()); + ++count; + } + + if(count != op->message_parts()) + throw Decoding_Error("PK_Verifier: signature size invalid"); + + return validate_signature(emsa->raw_data(), + &real_sig[0], real_sig.size()); + } + else + throw Decoding_Error("PK_Verifier: Unknown signature format " + + std::to_string(sig_format)); + } + catch(Invalid_Argument) { return false; } + } + +/* +* Verify a signature +*/ +bool PK_Verifier::validate_signature(const secure_vector& msg, + const byte sig[], size_t sig_len) + { + if(op->with_recovery()) + { + secure_vector output_of_key = op->verify_mr(sig, sig_len); + return emsa->verify(output_of_key, msg, op->max_input_bits()); + } + else + { + RandomNumberGenerator& rng = global_state().global_rng(); + + secure_vector encoded = + emsa->encoding_of(msg, op->max_input_bits(), rng); + + return op->verify(&encoded[0], encoded.size(), sig, sig_len); + } + } + +/* +* PK_Key_Agreement Constructor +*/ +PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& key, + const std::string& kdf_name) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + RandomNumberGenerator& rng = global_state().global_rng(); + + while(const Engine* engine = i.next()) + { + op = engine->get_key_agreement_op(key, rng); + if(op) + break; + } + + if(!op) + throw Lookup_Error("Key agreement with " + key.algo_name() + " not supported"); + + kdf = (kdf_name == "Raw") ? nullptr : get_kdf(kdf_name); + } + +SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, const byte in[], + size_t in_len, const byte params[], + size_t params_len) const + { + secure_vector z = op->agree(in, in_len); + + if(!kdf) + return z; + + return kdf->derive_key(key_len, z, params, params_len); + } + +} diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h new file mode 100644 index 000000000..cfa46109c --- /dev/null +++ b/src/lib/pubkey/pubkey.h @@ -0,0 +1,461 @@ +/* +* Public Key Interface +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PUBKEY_H__ +#define BOTAN_PUBKEY_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* The two types of signature format supported by Botan. +*/ +enum Signature_Format { IEEE_1363, DER_SEQUENCE }; + +/** +* Enum marking if protection against fault attacks should be used +*/ +enum Fault_Protection { + ENABLE_FAULT_PROTECTION, + DISABLE_FAULT_PROTECTION +}; + +/** +* Public Key Encryptor +*/ +class BOTAN_DLL PK_Encryptor + { + public: + + /** + * Encrypt a message. + * @param in the message as a byte array + * @param length the length of the above byte array + * @param rng the random number source to use + * @return encrypted message + */ + std::vector encrypt(const byte in[], size_t length, + RandomNumberGenerator& rng) const + { + return enc(in, length, rng); + } + + /** + * Encrypt a message. + * @param in the message + * @param rng the random number source to use + * @return encrypted message + */ + template + std::vector encrypt(const std::vector& in, + RandomNumberGenerator& rng) const + { + return enc(&in[0], in.size(), rng); + } + + /** + * Return the maximum allowed message size in bytes. + * @return maximum message size in bytes + */ + virtual size_t maximum_input_size() const = 0; + + PK_Encryptor() {} + virtual ~PK_Encryptor() {} + + PK_Encryptor(const PK_Encryptor&) = delete; + + PK_Encryptor& operator=(const PK_Encryptor&) = delete; + + private: + virtual std::vector enc(const byte[], size_t, + RandomNumberGenerator&) const = 0; + }; + +/** +* Public Key Decryptor +*/ +class BOTAN_DLL PK_Decryptor + { + public: + /** + * Decrypt a ciphertext. + * @param in the ciphertext as a byte array + * @param length the length of the above byte array + * @return decrypted message + */ + secure_vector decrypt(const byte in[], size_t length) const + { + return dec(in, length); + } + + /** + * Decrypt a ciphertext. + * @param in the ciphertext + * @return decrypted message + */ + template + secure_vector decrypt(const std::vector& in) const + { + return dec(&in[0], in.size()); + } + + PK_Decryptor() {} + virtual ~PK_Decryptor() {} + + PK_Decryptor(const PK_Decryptor&) = delete; + PK_Decryptor& operator=(const PK_Decryptor&) = delete; + + private: + virtual secure_vector dec(const byte[], size_t) const = 0; + }; + +/** +* Public Key Signer. Use the sign_message() functions for small +* messages. Use multiple calls update() to process large messages and +* generate the signature by finally calling signature(). +*/ +class BOTAN_DLL PK_Signer + { + public: + /** + * Sign a message. + * @param in the message to sign as a byte array + * @param length the length of the above byte array + * @param rng the rng to use + * @return signature + */ + std::vector sign_message(const byte in[], size_t length, + RandomNumberGenerator& rng); + + /** + * Sign a message. + * @param in the message to sign + * @param rng the rng to use + * @return signature + */ + std::vector sign_message(const std::vector& in, + RandomNumberGenerator& rng) + { return sign_message(&in[0], in.size(), rng); } + + std::vector sign_message(const secure_vector& in, + RandomNumberGenerator& rng) + { return sign_message(&in[0], in.size(), rng); } + + /** + * Add a message part (single byte). + * @param in the byte to add + */ + void update(byte in) { update(&in, 1); } + + /** + * Add a message part. + * @param in the message part to add as a byte array + * @param length the length of the above byte array + */ + void update(const byte in[], size_t length); + + /** + * Add a message part. + * @param in the message part to add + */ + void update(const std::vector& in) { update(&in[0], in.size()); } + + /** + * Get the signature of the so far processed message (provided by the + * calls to update()). + * @param rng the rng to use + * @return signature of the total message + */ + std::vector signature(RandomNumberGenerator& rng); + + /** + * Set the output format of the signature. + * @param format the signature format to use + */ + void set_output_format(Signature_Format format) { sig_format = format; } + + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + * @param format the signature format to use + * @param prot says if fault protection should be enabled + */ + PK_Signer(const Private_Key& key, + const std::string& emsa, + Signature_Format format = IEEE_1363, + Fault_Protection prot = ENABLE_FAULT_PROTECTION); + + PK_Signer(const PK_Signer&) = delete; + PK_Signer& operator=(const PK_Signer&) = delete; + + ~PK_Signer() { delete op; delete verify_op; delete emsa; } + private: + bool self_test_signature(const std::vector& msg, + const std::vector& sig) const; + + PK_Ops::Signature* op; + PK_Ops::Verification* verify_op; + EMSA* emsa; + Signature_Format sig_format; + }; + +/** +* Public Key Verifier. Use the verify_message() functions for small +* messages. Use multiple calls update() to process large messages and +* verify the signature by finally calling check_signature(). +*/ +class BOTAN_DLL PK_Verifier + { + public: + /** + * Verify a signature. + * @param msg the message that the signature belongs to, as a byte array + * @param msg_length the length of the above byte array msg + * @param sig the signature as a byte array + * @param sig_length the length of the above byte array sig + * @return true if the signature is valid + */ + bool verify_message(const byte msg[], size_t msg_length, + const byte sig[], size_t sig_length); + /** + * Verify a signature. + * @param msg the message that the signature belongs to + * @param sig the signature + * @return true if the signature is valid + */ + template + bool verify_message(const std::vector& msg, + const std::vector& sig) + { + return verify_message(&msg[0], msg.size(), + &sig[0], sig.size()); + } + + /** + * Add a message part (single byte) of the message corresponding to the + * signature to be verified. + * @param in the byte to add + */ + void update(byte in) { update(&in, 1); } + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param msg_part the new message part as a byte array + * @param length the length of the above byte array + */ + void update(const byte msg_part[], size_t length); + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param in the new message part + */ + void update(const std::vector& in) + { update(&in[0], in.size()); } + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified as a byte array + * @param length the length of the above byte array + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const byte sig[], size_t length); + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified + * @return true if the signature is valid, false otherwise + */ + template + bool check_signature(const std::vector& sig) + { + return check_signature(&sig[0], sig.size()); + } + + /** + * Set the format of the signatures fed to this verifier. + * @param format the signature format to use + */ + void set_input_format(Signature_Format format); + + /** + * Construct a PK Verifier. + * @param pub_key the public key to verify against + * @param emsa the EMSA to use (eg "EMSA3(SHA-1)") + * @param format the signature format to use + */ + PK_Verifier(const Public_Key& pub_key, + const std::string& emsa, + Signature_Format format = IEEE_1363); + + PK_Verifier(const PK_Verifier&) = delete; + PK_Verifier& operator=(const PK_Verifier&) = delete; + + ~PK_Verifier() { delete op; delete emsa; } + private: + bool validate_signature(const secure_vector& msg, + const byte sig[], size_t sig_len); + + PK_Ops::Verification* op; + EMSA* emsa; + Signature_Format sig_format; + }; + +/** +* Key used for key agreement +*/ +class BOTAN_DLL PK_Key_Agreement + { + public: + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const byte in[], + size_t in_len, + const byte params[], + size_t params_len) const; + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const std::vector& in, + const byte params[], + size_t params_len) const + { + return derive_key(key_len, &in[0], in.size(), + params, params_len); + } + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const byte in[], size_t in_len, + const std::string& params = "") const + { + return derive_key(key_len, in, in_len, + reinterpret_cast(params.data()), + params.length()); + } + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const std::vector& in, + const std::string& params = "") const + { + return derive_key(key_len, &in[0], in.size(), + reinterpret_cast(params.data()), + params.length()); + } + + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param kdf name of the KDF to use (or 'Raw' for no KDF) + */ + PK_Key_Agreement(const PK_Key_Agreement_Key& key, + const std::string& kdf); + + PK_Key_Agreement(const PK_Key_Agreement_Key&) = delete; + PK_Key_Agreement& operator=(const PK_Key_Agreement&) = delete; + + ~PK_Key_Agreement() { delete op; delete kdf; } + private: + PK_Ops::Key_Agreement* op; + KDF* kdf; + }; + +/** +* Encryption with an MR algorithm and an EME. +*/ +class BOTAN_DLL PK_Encryptor_EME : public PK_Encryptor + { + public: + size_t maximum_input_size() const; + + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param eme the EME to use + */ + PK_Encryptor_EME(const Public_Key& key, + const std::string& eme); + + ~PK_Encryptor_EME() { delete op; delete eme; } + private: + std::vector enc(const byte[], size_t, + RandomNumberGenerator& rng) const; + + PK_Ops::Encryption* op; + const EME* eme; + }; + +/** +* Decryption with an MR algorithm and an EME. +*/ +class BOTAN_DLL PK_Decryptor_EME : public PK_Decryptor + { + public: + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param eme the EME to use + */ + PK_Decryptor_EME(const Private_Key& key, + const std::string& eme); + + ~PK_Decryptor_EME() { delete op; delete eme; } + private: + secure_vector dec(const byte[], size_t) const; + + PK_Ops::Decryption* op; + const EME* eme; + }; + +/* +* Typedefs for compatability with 1.8 +*/ +typedef PK_Encryptor_EME PK_Encryptor_MR_with_EME; +typedef PK_Decryptor_EME PK_Decryptor_MR_with_EME; + +} + +#endif diff --git a/src/lib/pubkey/rsa/info.txt b/src/lib/pubkey/rsa/info.txt new file mode 100644 index 000000000..6171642bc --- /dev/null +++ b/src/lib/pubkey/rsa/info.txt @@ -0,0 +1,8 @@ +define RSA 20131128 + + +if_algo +keypair +libstate +numbertheory + diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp new file mode 100644 index 000000000..199ce6ad8 --- /dev/null +++ b/src/lib/pubkey/rsa/rsa.cpp @@ -0,0 +1,121 @@ +/* +* RSA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create a RSA private key +*/ +RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp) + { + if(bits < 1024) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + std::to_string(bits) + " bits long"); + if(exp < 3 || exp % 2 == 0) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + + do + { + p = random_prime(rng, (bits + 1) / 2, e); + q = random_prime(rng, bits - p.bits(), e); + n = p * q; + } while(n.bits() != bits); + + d = inverse_mod(e, lcm(p - 1, q - 1)); + d1 = d % (p - 1); + d2 = d % (q - 1); + c = inverse_mod(q, p); + + gen_check(rng); + } + +/* +* Check Private RSA Parameters +*/ +bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + if((e * d) % lcm(p - 1, q - 1) != 1) + return false; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-1)"); + } + +RSA_Private_Operation::RSA_Private_Operation(const RSA_PrivateKey& rsa, + RandomNumberGenerator& rng) : + n(rsa.get_n()), + q(rsa.get_q()), + c(rsa.get_c()), + powermod_e_n(rsa.get_e(), rsa.get_n()), + powermod_d1_p(rsa.get_d1(), rsa.get_p()), + powermod_d2_q(rsa.get_d2(), rsa.get_q()), + mod_p(rsa.get_p()) + { + BigInt k(rng, n.bits() - 1); + blinder = Blinder(powermod_e_n(k), inverse_mod(k, n), n); + } + +BigInt RSA_Private_Operation::private_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA private op - input is too large"); + + auto future_j1 = std::async(std::launch::async, powermod_d1_p, m); + BigInt j2 = powermod_d2_q(m); + BigInt j1 = future_j1.get(); + + j1 = mod_p.reduce(sub_mul(j1, j2, c)); + + return mul_add(j1, q, j2); + } + +secure_vector +RSA_Private_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + /* We don't check signatures against powermod_e_n here because + PK_Signer checks verification consistency for all signature + algorithms. + */ + + const BigInt m(msg, msg_len); + const BigInt x = blinder.unblind(private_op(blinder.blind(m))); + return BigInt::encode_1363(x, n.bytes()); + } + +/* +* RSA Decryption Operation +*/ +secure_vector +RSA_Private_Operation::decrypt(const byte msg[], size_t msg_len) + { + const BigInt m(msg, msg_len); + const BigInt x = blinder.unblind(private_op(blinder.blind(m))); + + BOTAN_ASSERT(m == powermod_e_n(x), + "RSA decrypt passed consistency check"); + + return BigInt::encode_locked(x); + } + +} diff --git a/src/lib/pubkey/rsa/rsa.h b/src/lib/pubkey/rsa/rsa.h new file mode 100644 index 000000000..4d9189d20 --- /dev/null +++ b/src/lib/pubkey/rsa/rsa.h @@ -0,0 +1,155 @@ +/* +* RSA +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RSA_H__ +#define BOTAN_RSA_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* RSA Public Key +*/ +class BOTAN_DLL RSA_PublicKey : public virtual IF_Scheme_PublicKey + { + public: + std::string algo_name() const { return "RSA"; } + + RSA_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + IF_Scheme_PublicKey(alg_id, key_bits) + {} + + /** + * Create a RSA_PublicKey + * @arg n the modulus + * @arg e the exponent + */ + RSA_PublicKey(const BigInt& n, const BigInt& e) : + IF_Scheme_PublicKey(n, e) + {} + + protected: + RSA_PublicKey() {} + }; + +/** +* RSA Private Key +*/ +class BOTAN_DLL RSA_PrivateKey : public RSA_PublicKey, + public IF_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + RSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) : + IF_Scheme_PrivateKey(rng, alg_id, key_bits) {} + + /** + * Construct a private key from the specified parameters. + * @param rng a random number generator + * @param p the first prime + * @param q the second prime + * @param e the exponent + * @param d if specified, this has to be d with + * exp * d = 1 mod (p - 1, q - 1). Leave it as 0 if you wish to + * the constructor to calculate it. + * @param n if specified, this must be n = p * q. Leave it as 0 + * if you wish to the constructor to calculate it. + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + const BigInt& p, const BigInt& q, + const BigInt& e, const BigInt& d = 0, + const BigInt& n = 0) : + IF_Scheme_PrivateKey(rng, p, q, e, d, n) {} + + /** + * Create a new private key with the specified bit length + * @param rng the random number generator to use + * @param bits the desired bit length of the private key + * @param exp the public exponent to be used + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp = 65537); + }; + +/** +* RSA private (decrypt/sign) operation +*/ +class BOTAN_DLL RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + RSA_Private_Operation(const RSA_PrivateKey& rsa, + RandomNumberGenerator& rng); + + size_t max_input_bits() const { return (n.bits() - 1); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + secure_vector decrypt(const byte msg[], size_t msg_len); + + private: + BigInt private_op(const BigInt& m) const; + + const BigInt& n; + const BigInt& q; + const BigInt& c; + Fixed_Exponent_Power_Mod powermod_e_n, powermod_d1_p, powermod_d2_q; + Modular_Reducer mod_p; + Blinder blinder; + }; + +/** +* RSA public (encrypt/verify) operation +*/ +class BOTAN_DLL RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), powermod_e_n(rsa.get_e(), rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + secure_vector verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + return powermod_e_n(m); + } + + const BigInt& n; + Fixed_Exponent_Power_Mod powermod_e_n; + }; + +} + +#endif diff --git a/src/lib/pubkey/rw/info.txt b/src/lib/pubkey/rw/info.txt new file mode 100644 index 000000000..486ede47f --- /dev/null +++ b/src/lib/pubkey/rw/info.txt @@ -0,0 +1,8 @@ +define RW 20131128 + + +if_algo +keypair +libstate +numbertheory + diff --git a/src/lib/pubkey/rw/rw.cpp b/src/lib/pubkey/rw/rw.cpp new file mode 100644 index 000000000..63e7977d8 --- /dev/null +++ b/src/lib/pubkey/rw/rw.cpp @@ -0,0 +1,130 @@ +/* +* Rabin-Williams +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create a Rabin-Williams private key +*/ +RW_PrivateKey::RW_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp) + { + if(bits < 1024) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + std::to_string(bits) + " bits long"); + if(exp < 2 || exp % 2 == 1) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + + do + { + p = random_prime(rng, (bits + 1) / 2, e / 2, 3, 4); + q = random_prime(rng, bits - p.bits(), e / 2, ((p % 8 == 3) ? 7 : 3), 8); + n = p * q; + } while(n.bits() != bits); + + d = inverse_mod(e, lcm(p - 1, q - 1) >> 1); + d1 = d % (p - 1); + d2 = d % (q - 1); + c = inverse_mod(q, p); + + gen_check(rng); + } + +/* +* Check Private Rabin-Williams Parameters +*/ +bool RW_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + if((e * d) % (lcm(p - 1, q - 1) / 2) != 1) + return false; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA2(SHA-1)"); + } + +RW_Signature_Operation::RW_Signature_Operation(const RW_PrivateKey& rw) : + n(rw.get_n()), + e(rw.get_e()), + q(rw.get_q()), + c(rw.get_c()), + powermod_d1_p(rw.get_d1(), rw.get_p()), + powermod_d2_q(rw.get_d2(), rw.get_q()), + mod_p(rw.get_p()) + { + } + +secure_vector +RW_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + if(!blinder.initialized()) + { + BigInt k(rng, std::min(160, n.bits() - 1)); + blinder = Blinder(power_mod(k, e, n), inverse_mod(k, n), n); + } + + BigInt i(msg, msg_len); + + if(i >= n || i % 16 != 12) + throw Invalid_Argument("Rabin-Williams: invalid input"); + + if(jacobi(i, n) != 1) + i >>= 1; + + i = blinder.blind(i); + + auto future_j1 = std::async(std::launch::async, powermod_d1_p, i); + const BigInt j2 = powermod_d2_q(i); + BigInt j1 = future_j1.get(); + + j1 = mod_p.reduce(sub_mul(j1, j2, c)); + + const BigInt r = blinder.unblind(mul_add(j1, q, j2)); + + return BigInt::encode_1363(std::min(r, n - r), n.bytes()); + } + +secure_vector +RW_Verification_Operation::verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + + if((m > (n >> 1)) || m.is_negative()) + throw Invalid_Argument("RW signature verification: m > n / 2 || m < 0"); + + BigInt r = powermod_e_n(m); + if(r % 16 == 12) + return BigInt::encode_locked(r); + if(r % 8 == 6) + return BigInt::encode_locked(2*r); + + r = n - r; + if(r % 16 == 12) + return BigInt::encode_locked(r); + if(r % 8 == 6) + return BigInt::encode_locked(2*r); + + throw Invalid_Argument("RW signature verification: Invalid signature"); + } + +} diff --git a/src/lib/pubkey/rw/rw.h b/src/lib/pubkey/rw/rw.h new file mode 100644 index 000000000..1e918e70c --- /dev/null +++ b/src/lib/pubkey/rw/rw.h @@ -0,0 +1,107 @@ +/* +* Rabin-Williams +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RW_H__ +#define BOTAN_RW_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Rabin-Williams Public Key +*/ +class BOTAN_DLL RW_PublicKey : public virtual IF_Scheme_PublicKey + { + public: + std::string algo_name() const { return "RW"; } + + RW_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + IF_Scheme_PublicKey(alg_id, key_bits) + {} + + RW_PublicKey(const BigInt& mod, const BigInt& exponent) : + IF_Scheme_PublicKey(mod, exponent) + {} + + protected: + RW_PublicKey() {} + }; + +/** +* Rabin-Williams Private Key +*/ +class BOTAN_DLL RW_PrivateKey : public RW_PublicKey, + public IF_Scheme_PrivateKey + { + public: + RW_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + RandomNumberGenerator& rng) : + IF_Scheme_PrivateKey(rng, alg_id, key_bits) {} + + RW_PrivateKey(RandomNumberGenerator& rng, + const BigInt& p, const BigInt& q, + const BigInt& e, const BigInt& d = 0, + const BigInt& n = 0) : + IF_Scheme_PrivateKey(rng, p, q, e, d, n) {} + + RW_PrivateKey(RandomNumberGenerator& rng, size_t bits, size_t = 2); + + bool check_key(RandomNumberGenerator& rng, bool) const; + }; + +/** +* Rabin-Williams Signature Operation +*/ +class BOTAN_DLL RW_Signature_Operation : public PK_Ops::Signature + { + public: + RW_Signature_Operation(const RW_PrivateKey& rw); + + size_t max_input_bits() const { return (n.bits() - 1); } + + secure_vector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const BigInt& n; + const BigInt& e; + const BigInt& q; + const BigInt& c; + + Fixed_Exponent_Power_Mod powermod_d1_p, powermod_d2_q; + Modular_Reducer mod_p; + Blinder blinder; + }; + +/** +* Rabin-Williams Verification Operation +*/ +class BOTAN_DLL RW_Verification_Operation : public PK_Ops::Verification + { + public: + RW_Verification_Operation(const RW_PublicKey& rw) : + n(rw.get_n()), powermod_e_n(rw.get_e(), rw.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector verify_mr(const byte msg[], size_t msg_len); + + private: + const BigInt& n; + Fixed_Exponent_Power_Mod powermod_e_n; + }; + +} + +#endif diff --git a/src/lib/pubkey/workfactor.cpp b/src/lib/pubkey/workfactor.cpp new file mode 100644 index 000000000..b917ce52d --- /dev/null +++ b/src/lib/pubkey/workfactor.cpp @@ -0,0 +1,50 @@ +/* +* Public Key Work Factor Functions +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +size_t dl_work_factor(size_t bits) + { + /* + Based on GNFS work factors. Constant is 1.43 times the asymptotic + value; I'm not sure but I believe that came from a paper on 'real + world' runtimes, but I don't remember where now. + + Sample return values: + |512| -> 64 + |1024| -> 86 + |1536| -> 102 + |2048| -> 116 + |3072| -> 138 + |4096| -> 155 + |8192| -> 206 + + For DL algos, we use an exponent of twice the size of the result; + the assumption is that an arbitrary discrete log on a group of size + bits would take about 2^n effort, and thus using an exponent of + size 2^(2*n) implies that all available attacks are about as easy + (as e.g Pollard's kangaroo algorithm can compute the DL in sqrt(x) + operations) while minimizing the exponent size for performance + reasons. + */ + + const size_t MIN_WORKFACTOR = 64; + + // approximates natural logarithm of p + const double log_p = bits / 1.4426; + + const double strength = + 2.76 * std::pow(log_p, 1.0/3.0) * std::pow(std::log(log_p), 2.0/3.0); + + return std::max(static_cast(strength), MIN_WORKFACTOR); + } + +} diff --git a/src/lib/pubkey/workfactor.h b/src/lib/pubkey/workfactor.h new file mode 100644 index 000000000..179b580e7 --- /dev/null +++ b/src/lib/pubkey/workfactor.h @@ -0,0 +1,24 @@ +/* +* Public Key Work Factor Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_WORKFACTOR_H__ +#define BOTAN_WORKFACTOR_H__ + +#include + +namespace Botan { + +/** +* Estimate work factor for discrete logarithm +* @param prime_group_size size of the group in bits +* @return estimated security level for this group +*/ +size_t dl_work_factor(size_t prime_group_size); + +} + +#endif diff --git a/src/lib/pubkey/x509_key.cpp b/src/lib/pubkey/x509_key.cpp new file mode 100644 index 000000000..10395837c --- /dev/null +++ b/src/lib/pubkey/x509_key.cpp @@ -0,0 +1,111 @@ +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace X509 { + +std::vector BER_encode(const Public_Key& key) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(key.algorithm_identifier()) + .encode(key.x509_subject_public_key(), BIT_STRING) + .end_cons() + .get_contents_unlocked(); + } + +/* +* PEM encode a X.509 public key +*/ +std::string PEM_encode(const Public_Key& key) + { + return PEM_Code::encode(X509::BER_encode(key), + "PUBLIC KEY"); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(DataSource& source) + { + try { + AlgorithmIdentifier alg_id; + secure_vector key_bits; + + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .verify_end() + .end_cons(); + } + else + { + DataSource_Memory ber( + PEM_Code::decode_check_label(source, "PUBLIC KEY") + ); + + BER_Decoder(ber) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .verify_end() + .end_cons(); + } + + if(key_bits.empty()) + throw Decoding_Error("X.509 public key decoding failed"); + + return make_public_key(alg_id, key_bits); + } + catch(Decoding_Error) + { + throw Decoding_Error("X.509 public key decoding failed"); + } + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::string& fsname) + { + DataSource_Stream source(fsname, true); + return X509::load_key(source); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::vector& mem) + { + DataSource_Memory source(mem); + return X509::load_key(source); + } + +/* +* Make a copy of this public key +*/ +Public_Key* copy_key(const Public_Key& key) + { + DataSource_Memory source(PEM_encode(key)); + return X509::load_key(source); + } + +} + +} diff --git a/src/lib/pubkey/x509_key.h b/src/lib/pubkey/x509_key.h new file mode 100644 index 000000000..14e5c9699 --- /dev/null +++ b/src/lib/pubkey/x509_key.h @@ -0,0 +1,74 @@ +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_PUBLIC_KEY_H__ +#define BOTAN_X509_PUBLIC_KEY_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* The two types of X509 encoding supported by Botan. +*/ +enum X509_Encoding { RAW_BER, PEM }; + +/** +* This namespace contains functions for handling X.509 public keys +*/ +namespace X509 { + +/** +* BER encode a key +* @param key the public key to encode +* @return BER encoding of this key +*/ +BOTAN_DLL std::vector BER_encode(const Public_Key& key); + +/** +* PEM encode a public key into a string. +* @param key the key to encode +* @return PEM encoded key +*/ +BOTAN_DLL std::string PEM_encode(const Public_Key& key); + +/** +* Create a public key from a data source. +* @param source the source providing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_DLL Public_Key* load_key(DataSource& source); + +/** +* Create a public key from a file +* @param filename pathname to the file to load +* @return new public key object +*/ +BOTAN_DLL Public_Key* load_key(const std::string& filename); + +/** +* Create a public key from a memory region. +* @param enc the memory region containing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_DLL Public_Key* load_key(const std::vector& enc); + +/** +* Copy a key. +* @param key the public key to copy +* @return new public key object +*/ +BOTAN_DLL Public_Key* copy_key(const Public_Key& key); + +} + +} + +#endif diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng/auto_rng.h new file mode 100644 index 000000000..13201f251 --- /dev/null +++ b/src/lib/rng/auto_rng/auto_rng.h @@ -0,0 +1,41 @@ +/* +* Auto Seeded RNG +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AUTO_SEEDING_RNG_H__ +#define BOTAN_AUTO_SEEDING_RNG_H__ + +#include +#include +#include + +namespace Botan { + +class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator + { + public: + void randomize(byte out[], size_t len) + { m_rng->randomize(out, len); } + + bool is_seeded() const { return m_rng->is_seeded(); } + + void clear() { m_rng->clear(); } + + std::string name() const { return m_rng->name(); } + + void reseed(size_t poll_bits = 256) { m_rng->reseed(poll_bits); } + + void add_entropy(const byte in[], size_t len) + { m_rng->add_entropy(in, len); } + + AutoSeeded_RNG() : m_rng(RandomNumberGenerator::make_rng()) {} + private: + std::unique_ptr m_rng; + }; + +} + +#endif diff --git a/src/lib/rng/auto_rng/info.txt b/src/lib/rng/auto_rng/info.txt new file mode 100644 index 000000000..848c06ac3 --- /dev/null +++ b/src/lib/rng/auto_rng/info.txt @@ -0,0 +1,8 @@ +define AUTO_SEEDING_RNG 20131128 + + +hmac_rng +hmac +sha2_32 +sha2_64 + diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp new file mode 100644 index 000000000..98ae6439e --- /dev/null +++ b/src/lib/rng/hmac_rng/hmac_rng.cpp @@ -0,0 +1,205 @@ +/* +* HMAC_RNG +* (C) 2008-2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void hmac_prf(MessageAuthenticationCode& prf, + secure_vector& K, + u32bit& counter, + const std::string& label) + { + typedef std::chrono::high_resolution_clock clock; + + auto timestamp = clock::now().time_since_epoch().count(); + + prf.update(K); + prf.update(label); + prf.update_be(timestamp); + prf.update_be(counter); + prf.final(&K[0]); + + ++counter; + } + +} + +/* +* HMAC_RNG Constructor +*/ +HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor, + MessageAuthenticationCode* prf) : + m_extractor(extractor), m_prf(prf) + { + if(!m_prf->valid_keylength(m_extractor->output_length()) || + !m_extractor->valid_keylength(m_prf->output_length())) + throw Invalid_Argument("HMAC_RNG: Bad algo combination " + + m_extractor->name() + " and " + + m_prf->name()); + + // First PRF inputs are all zero, as specified in section 2 + m_K.resize(m_prf->output_length()); + + /* + Normally we want to feedback PRF outputs to the extractor function + to ensure a single bad poll does not reduce entropy. Thus in reseed + we'll want to invoke the PRF before we reset the PRF key, but until + the first reseed the PRF is unkeyed. Rather than trying to keep + track of this, just set the initial PRF key to constant zero. + Since all PRF inputs in the first reseed are constants, this + amounts to suffixing the seed in the first poll with a fixed + constant string. + + The PRF key will not be used to generate outputs until after reseed + sets m_seeded to true. + */ + secure_vector prf_key(m_extractor->output_length()); + m_prf->set_key(prf_key); + + /* + Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key. + + This will be used during the first extraction sequence; XTS values + after this one are generated using the PRF. + + If I understand the E-t-E paper correctly (specifically Section 4), + using this fixed extractor key is safe to do. + */ + m_extractor->set_key(prf->process("Botan HMAC_RNG XTS")); + } + +/* +* Generate a buffer of random bytes +*/ +void HMAC_RNG::randomize(byte out[], size_t length) + { + if(!is_seeded()) + { + reseed(256); + if(!is_seeded()) + throw PRNG_Unseeded(name()); + } + + const size_t max_per_prf_iter = m_prf->output_length() / 2; + + /* + HMAC KDF as described in E-t-E, using a CTXinfo of "rng" + */ + while(length) + { + hmac_prf(*m_prf, m_K, m_counter, "rng"); + + const size_t copied = std::min(length, max_per_prf_iter); + + copy_mem(out, &m_K[0], copied); + out += copied; + length -= copied; + + m_output_since_reseed += copied; + + if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED) + reseed(BOTAN_RNG_RESEED_POLL_BITS); + } + } + +/* +* Poll for entropy and reset the internal keys +*/ +void HMAC_RNG::reseed(size_t poll_bits) + { + /* + Using the terminology of E-t-E, XTR is the MAC function (normally + HMAC) seeded with XTS (below) and we form SKM, the key material, by + polling as many sources as we think needed to reach our polling + goal. We then also include feedback of the current PRK so that + a bad poll doesn't wipe us out. + */ + + Entropy_Accumulator_BufferedComputation accum(*m_extractor, poll_bits); + + global_state().poll_available_sources(accum); + + /* + * It is necessary to feed forward poll data. Otherwise, a good poll + * (collecting a large amount of conditional entropy) followed by a + * bad one (collecting little) would be unsafe. Do this by + * generating new PRF outputs using the previous key and feeding + * them into the extractor function. + * + * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF + * output using the CTXinfo "reseed". Provide these values as input + * to the extractor function. + */ + hmac_prf(*m_prf, m_K, m_counter, "rng"); + m_extractor->update(m_K); // K is the CTXinfo=rng PRF output + + hmac_prf(*m_prf, m_K, m_counter, "reseed"); + m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output + + /* Now derive the new PRK using everything that has been fed into + the extractor, and set the PRF key to that */ + m_prf->set_key(m_extractor->final()); + + // Now generate a new PRF output to use as the XTS extractor salt + hmac_prf(*m_prf, m_K, m_counter, "xts"); + m_extractor->set_key(m_K); + + // Reset state + zeroise(m_K); + m_counter = 0; + + m_collected_entropy_estimate = + std::min(m_collected_entropy_estimate + accum.bits_collected(), + m_extractor->output_length() * 8); + + m_output_since_reseed = 0; + } + +bool HMAC_RNG::is_seeded() const + { + return (m_collected_entropy_estimate >= 256); + } + +/* +* Add user-supplied entropy to the extractor input +*/ +void HMAC_RNG::add_entropy(const byte input[], size_t length) + { + m_extractor->update(input, length); + reseed(BOTAN_RNG_RESEED_POLL_BITS); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC_RNG::clear() + { + m_collected_entropy_estimate = 0; + m_extractor->clear(); + m_prf->clear(); + zeroise(m_K); + m_counter = 0; + } + +/* +* Return the name of this type +*/ +std::string HMAC_RNG::name() const + { + return "HMAC_RNG(" + m_extractor->name() + "," + m_prf->name() + ")"; + } + +} diff --git a/src/lib/rng/hmac_rng/hmac_rng.h b/src/lib/rng/hmac_rng/hmac_rng.h new file mode 100644 index 000000000..8fee5be5a --- /dev/null +++ b/src/lib/rng/hmac_rng/hmac_rng.h @@ -0,0 +1,57 @@ +/* +* HMAC RNG +* (C) 2008,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HMAC_RNG_H__ +#define BOTAN_HMAC_RNG_H__ + +#include +#include +#include + +namespace Botan { + +/** +* HMAC_RNG - based on the design described in "On Extract-then-Expand +* Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk +* (henceforce, 'E-t-E') +* +* However it actually can be parameterized with any two MAC functions, +* not restricted to HMAC (this variation is also described in +* Krawczyk's paper), for instance one could use HMAC(SHA-512) as the +* extractor and CMAC(AES-256) as the PRF. +*/ +class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator + { + public: + void randomize(byte buf[], size_t len); + bool is_seeded() const; + void clear(); + std::string name() const; + + void reseed(size_t poll_bits); + void add_entropy(const byte[], size_t); + + /** + * @param extractor a MAC used for extracting the entropy + * @param prf a MAC used as a PRF using HKDF construction + */ + HMAC_RNG(MessageAuthenticationCode* extractor, + MessageAuthenticationCode* prf); + private: + std::unique_ptr m_extractor; + std::unique_ptr m_prf; + + size_t m_collected_entropy_estimate = 0; + size_t m_output_since_reseed = 0; + + secure_vector m_K; + u32bit m_counter = 0; + }; + +} + +#endif diff --git a/src/lib/rng/hmac_rng/info.txt b/src/lib/rng/hmac_rng/info.txt new file mode 100644 index 000000000..36a8a7a34 --- /dev/null +++ b/src/lib/rng/hmac_rng/info.txt @@ -0,0 +1,5 @@ +define HMAC_RNG 20131128 + + +mac + diff --git a/src/lib/rng/info.txt b/src/lib/rng/info.txt new file mode 100644 index 000000000..4c88ba382 --- /dev/null +++ b/src/lib/rng/info.txt @@ -0,0 +1,3 @@ + +entropy + diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp new file mode 100644 index 000000000..12a6c163e --- /dev/null +++ b/src/lib/rng/rng.cpp @@ -0,0 +1,34 @@ +/* +* Random Number Generator Base +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +RandomNumberGenerator* RandomNumberGenerator::make_rng() + { + return make_rng(global_state().algorithm_factory()).release(); + } + +/* +* Create and seed a new RNG object +*/ +std::unique_ptr RandomNumberGenerator::make_rng(Algorithm_Factory& af) + { + std::unique_ptr rng( + new HMAC_RNG(af.make_mac("HMAC(SHA-512)"), + af.make_mac("HMAC(SHA-256)")) + ); + + rng->reseed(256); + + return rng; + } + +} diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h new file mode 100644 index 000000000..8664ccbf7 --- /dev/null +++ b/src/lib/rng/rng.h @@ -0,0 +1,174 @@ +/* +* RandomNumberGenerator +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__ +#define BOTAN_RANDOM_NUMBER_GENERATOR_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents a random number (RNG) generator object. +*/ +class BOTAN_DLL RandomNumberGenerator + { + public: + /** + * Create a seeded and active RNG object for general application use + * Added in 1.8.0 + */ + static RandomNumberGenerator* make_rng(); + + /** + * Create a seeded and active RNG object for general application use + * Added in 1.11.5 + */ + static std::unique_ptr make_rng(class Algorithm_Factory& af); + + /** + * Randomize a byte array. + * @param output the byte array to hold the random output. + * @param length the length of the byte array output. + */ + virtual void randomize(byte output[], size_t length) = 0; + + /** + * Return a random vector + * @param bytes number of bytes in the result + * @return randomized vector of length bytes + */ + secure_vector random_vec(size_t bytes) + { + secure_vector output(bytes); + randomize(&output[0], output.size()); + return output; + } + + /** + * Return a random byte + * @return random byte + */ + byte next_byte() + { + byte out; + this->randomize(&out, 1); + return out; + } + + /** + * Check whether this RNG is seeded. + * @return true if this RNG was already seeded, false otherwise. + */ + virtual bool is_seeded() const = 0; + + /** + * Clear all internally held values of this RNG. + */ + virtual void clear() = 0; + + /** + * Return the name of this object + */ + virtual std::string name() const = 0; + + /** + * Seed this RNG using the entropy sources it contains. + * @param bits_to_collect is the number of bits of entropy to + attempt to gather from the entropy sources + */ + virtual void reseed(size_t bits_to_collect) = 0; + + /** + * Add entropy to this RNG. + * @param in a byte array containg the entropy to be added + * @param length the length of the byte array in + */ + virtual void add_entropy(const byte in[], size_t length) = 0; + + /* + * Never copy a RNG, create a new one + */ + RandomNumberGenerator(const RandomNumberGenerator& rng) = delete; + RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete; + + RandomNumberGenerator() {} + virtual ~RandomNumberGenerator() {} + }; + +/** +* Null/stub RNG - fails if you try to use it for anything +*/ +class BOTAN_DLL Null_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], size_t) override { throw PRNG_Unseeded("Null_RNG"); } + + void clear() override {} + + std::string name() const override { return "Null_RNG"; } + + void reseed(size_t) override {} + bool is_seeded() const override { return false; } + void add_entropy(const byte[], size_t) override {} + }; + +/** +* Wraps access to a RNG in a mutex +*/ +class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator + { + public: + void randomize(byte out[], size_t len) + { + std::lock_guard lock(m_mutex); + m_rng->randomize(out, len); + } + + bool is_seeded() const + { + std::lock_guard lock(m_mutex); + return m_rng->is_seeded(); + } + + void clear() + { + std::lock_guard lock(m_mutex); + m_rng->clear(); + } + + std::string name() const + { + std::lock_guard lock(m_mutex); + return m_rng->name(); + } + + void reseed(size_t poll_bits) + { + std::lock_guard lock(m_mutex); + m_rng->reseed(poll_bits); + } + + void add_entropy(const byte in[], size_t len) + { + std::lock_guard lock(m_mutex); + m_rng->add_entropy(in, len); + } + + Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {} + private: + mutable std::mutex m_mutex; + std::unique_ptr m_rng; + }; + +} + +#endif diff --git a/src/lib/rng/x931_rng/info.txt b/src/lib/rng/x931_rng/info.txt new file mode 100644 index 000000000..beab0dbfd --- /dev/null +++ b/src/lib/rng/x931_rng/info.txt @@ -0,0 +1,5 @@ +define X931_RNG 20131128 + + +block + diff --git a/src/lib/rng/x931_rng/x931_rng.cpp b/src/lib/rng/x931_rng/x931_rng.cpp new file mode 100644 index 000000000..b36f87106 --- /dev/null +++ b/src/lib/rng/x931_rng/x931_rng.cpp @@ -0,0 +1,146 @@ +/* +* ANSI X9.31 RNG +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Generate a buffer of random bytes +*/ +void ANSI_X931_RNG::randomize(byte out[], size_t length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + while(length) + { + if(position == R.size()) + update_buffer(); + + const size_t copied = std::min(length, R.size() - position); + + copy_mem(out, &R[position], copied); + out += copied; + length -= copied; + position += copied; + } + } + +/* +* Refill the internal state +*/ +void ANSI_X931_RNG::update_buffer() + { + const size_t BLOCK_SIZE = cipher->block_size(); + + secure_vector DT = prng->random_vec(BLOCK_SIZE); + cipher->encrypt(DT); + + xor_buf(&R[0], &V[0], &DT[0], BLOCK_SIZE); + cipher->encrypt(R); + + xor_buf(&V[0], &R[0], &DT[0], BLOCK_SIZE); + cipher->encrypt(V); + + position = 0; + } + +/* +* Reset V and the cipher key with new values +*/ +void ANSI_X931_RNG::rekey() + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(prng->is_seeded()) + { + cipher->set_key(prng->random_vec(cipher->maximum_keylength())); + + if(V.size() != BLOCK_SIZE) + V.resize(BLOCK_SIZE); + prng->randomize(&V[0], V.size()); + + update_buffer(); + } + } + +/* +* Reseed the internal state +*/ +void ANSI_X931_RNG::reseed(size_t poll_bits) + { + prng->reseed(poll_bits); + rekey(); + } + +/* +* Add some entropy to the underlying PRNG +*/ +void ANSI_X931_RNG::add_entropy(const byte input[], size_t length) + { + prng->add_entropy(input, length); + rekey(); + } + +/* +* Check if the the PRNG is seeded +*/ +bool ANSI_X931_RNG::is_seeded() const + { + return (V.size() > 0); + } + +/* +* Clear memory of sensitive data +*/ +void ANSI_X931_RNG::clear() + { + cipher->clear(); + prng->clear(); + zeroise(R); + V.clear(); + + position = 0; + } + +/* +* Return the name of this type +*/ +std::string ANSI_X931_RNG::name() const + { + return "X9.31(" + cipher->name() + ")"; + } + +/* +* ANSI X931 RNG Constructor +*/ +ANSI_X931_RNG::ANSI_X931_RNG(BlockCipher* cipher_in, + RandomNumberGenerator* prng_in) + { + if(!prng_in || !cipher_in) + throw Invalid_Argument("ANSI_X931_RNG constructor: NULL arguments"); + + cipher = cipher_in; + prng = prng_in; + + R.resize(cipher->block_size()); + position = 0; + } + +/* +* ANSI X931 RNG Destructor +*/ +ANSI_X931_RNG::~ANSI_X931_RNG() + { + delete cipher; + delete prng; + } + +} diff --git a/src/lib/rng/x931_rng/x931_rng.h b/src/lib/rng/x931_rng/x931_rng.h new file mode 100644 index 000000000..8052cedc3 --- /dev/null +++ b/src/lib/rng/x931_rng/x931_rng.h @@ -0,0 +1,50 @@ +/* +* ANSI X9.31 RNG +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ANSI_X931_RNG_H__ +#define BOTAN_ANSI_X931_RNG_H__ + +#include +#include + +namespace Botan { + +/** +* ANSI X9.31 RNG +*/ +class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], size_t); + bool is_seeded() const; + void clear(); + std::string name() const; + + void reseed(size_t poll_bits); + void add_entropy(const byte[], size_t); + + /** + * @param cipher the block cipher to use in this PRNG + * @param rng the underlying PRNG for generating inputs + * (eg, an HMAC_RNG) + */ + ANSI_X931_RNG(BlockCipher* cipher, + RandomNumberGenerator* rng); + ~ANSI_X931_RNG(); + private: + void rekey(); + void update_buffer(); + + BlockCipher* cipher; + RandomNumberGenerator* prng; + secure_vector V, R; + size_t position; + }; + +} + +#endif diff --git a/src/lib/selftest/info.txt b/src/lib/selftest/info.txt new file mode 100644 index 000000000..265cc0bac --- /dev/null +++ b/src/lib/selftest/info.txt @@ -0,0 +1,8 @@ +define SELFTESTS 20131128 + + +algo_factory +filters +aead_filt +core_engine + diff --git a/src/lib/selftest/selftest.cpp b/src/lib/selftest/selftest.cpp new file mode 100644 index 000000000..87111b292 --- /dev/null +++ b/src/lib/selftest/selftest.cpp @@ -0,0 +1,342 @@ +/* +* Startup Self Tests +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Perform a Known Answer Test +*/ +std::string test_filter_kat(Filter* filter, + const std::string& input, + const std::string& expected) + { + try + { + Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder); + pipe.process_msg(input); + + const std::string got = pipe.read_all_as_string(); + + const bool same = (got == expected); + + if(same) + return "passed"; + else + return (std::string("got ") + got + " expected " + expected); + } + catch(std::exception& e) + { + return std::string("exception ") + e.what(); + } + } + +} + +/* +* Run a set of KATs +*/ +std::map +algorithm_kat_detailed(const SCAN_Name& algo_name, + const std::map& vars, + Algorithm_Factory& af) + { + const std::string& algo = algo_name.algo_name_and_args(); + + std::vector providers = af.providers_of(algo); + std::map all_results; + + if(providers.empty()) // no providers, nothing to do + return all_results; + + const std::string input = search_map(vars, std::string("input")); + const std::string output = search_map(vars, std::string("output")); + + SymmetricKey key(search_map(vars, std::string("key"))); + InitializationVector iv(search_map(vars, std::string("iv"))); + + for(size_t i = 0; i != providers.size(); ++i) + { + const std::string provider = providers[i]; + + if(const HashFunction* proto = + af.prototype_hash_function(algo, provider)) + { + Filter* filt = new Hash_Filter(proto->clone()); + all_results[provider] = test_filter_kat(filt, input, output); + } + else if(const MessageAuthenticationCode* proto = + af.prototype_mac(algo, provider)) + { + Keyed_Filter* filt = new MAC_Filter(proto->clone(), key); + all_results[provider] = test_filter_kat(filt, input, output); + } + else if(const StreamCipher* proto = + af.prototype_stream_cipher(algo, provider)) + { + Keyed_Filter* filt = new StreamCipher_Filter(proto->clone()); + filt->set_key(key); + filt->set_iv(iv); + + all_results[provider] = test_filter_kat(filt, input, output); + } + else if(const BlockCipher* proto = + af.prototype_block_cipher(algo, provider)) + { + Keyed_Filter* enc = get_cipher_mode(proto, ENCRYPTION, + algo_name.cipher_mode(), + algo_name.cipher_mode_pad()); + + Keyed_Filter* dec = get_cipher_mode(proto, DECRYPTION, + algo_name.cipher_mode(), + algo_name.cipher_mode_pad()); + + if(!enc || !dec) + { + delete enc; + delete dec; + continue; + } + + enc->set_key(key); + + if(enc->valid_iv_length(iv.length())) + enc->set_iv(iv); + else if(!enc->valid_iv_length(0)) + throw Invalid_IV_Length(algo, iv.length()); + + dec->set_key(key); + + if(dec->valid_iv_length(iv.length())) + dec->set_iv(iv); + else if(!dec->valid_iv_length(0)) + throw Invalid_IV_Length(algo, iv.length()); + + const std::vector ad = hex_decode(search_map(vars, std::string("ad"))); + + if(!ad.empty()) + { + if(AEAD_Filter* enc_aead = dynamic_cast(enc)) + { + enc_aead->set_associated_data(&ad[0], ad.size()); + + if(AEAD_Filter* dec_aead = dynamic_cast(dec)) + dec_aead->set_associated_data(&ad[0], ad.size()); + } + } + + all_results[provider + " (encrypt)"] = test_filter_kat(enc, input, output); + all_results[provider + " (decrypt)"] = test_filter_kat(dec, output, input); + } + } + + return all_results; + } + +std::map +algorithm_kat(const SCAN_Name& algo_name, + const std::map& vars, + Algorithm_Factory& af) + { + const auto result = algorithm_kat_detailed(algo_name, vars, af); + + std::map pass_or_fail; + + for(auto i : result) + pass_or_fail[i.first] = (i.second == "passed"); + + return pass_or_fail; + } + +namespace { + +void verify_results(const std::string& algo, + const std::map& results) + { + for(auto i = results.begin(); i != results.end(); ++i) + { + if(i->second != "passed") + throw Self_Test_Failure(algo + " self-test failed (" + i->second + ")" + + " with provider " + i->first); + } + } + +void hash_test(Algorithm_Factory& af, + const std::string& name, + const std::string& in, + const std::string& out) + { + std::map vars; + vars["input"] = in; + vars["output"] = out; + + verify_results(name, algorithm_kat_detailed(name, vars, af)); + } + +void mac_test(Algorithm_Factory& af, + const std::string& name, + const std::string& in, + const std::string& out, + const std::string& key) + { + std::map vars; + vars["input"] = in; + vars["output"] = out; + vars["key"] = key; + + verify_results(name, algorithm_kat_detailed(name, vars, af)); + } + +/* +* Perform a KAT for a cipher +*/ +void cipher_kat(Algorithm_Factory& af, + const std::string& algo, + const std::string& key_str, + const std::string& iv_str, + const std::string& in, + const std::string& ecb_out, + const std::string& cbc_out, + const std::string& cfb_out, + const std::string& ofb_out, + const std::string& ctr_out) + { + SymmetricKey key(key_str); + InitializationVector iv(iv_str); + + std::map vars; + vars["key"] = key_str; + vars["iv"] = iv_str; + vars["input"] = in; + + std::map results; + + vars["output"] = ecb_out; + verify_results(algo + "/ECB", algorithm_kat_detailed(algo + "/ECB", vars, af)); + + vars["output"] = cbc_out; + verify_results(algo + "/CBC", + algorithm_kat_detailed(algo + "/CBC/NoPadding", vars, af)); + + vars["output"] = cfb_out; + verify_results(algo + "/CFB", algorithm_kat_detailed(algo + "/CFB", vars, af)); + + vars["output"] = ofb_out; + verify_results(algo + "/OFB", algorithm_kat_detailed(algo + "/OFB", vars, af)); + + vars["output"] = ctr_out; + verify_results(algo + "/CTR", algorithm_kat_detailed(algo + "/CTR-BE", vars, af)); + } + +} + +/* +* Perform Self Tests +*/ +bool passes_self_tests(Algorithm_Factory& af) + { + try + { + confirm_startup_self_tests(af); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +/* +* Perform Self Tests +*/ +void confirm_startup_self_tests(Algorithm_Factory& af) + { + cipher_kat(af, "DES", + "0123456789ABCDEF", "1234567890ABCDEF", + "4E6F77206973207468652074696D6520666F7220616C6C20", + "3FA40E8A984D48156A271787AB8883F9893D51EC4B563B53", + "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6", + "F3096249C7F46E51A69E839B1A92F78403467133898EA622", + "F3096249C7F46E5135F24A242EEB3D3F3D6D5BE3255AF8C3", + "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75"); + + cipher_kat(af, "TripleDES", + "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E", + "C141B5FCCD28DC8A", + "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68", + "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4", + "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9", + "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B", + "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62", + "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371"); + + cipher_kat(af, "AES-128", + "2B7E151628AED2A6ABF7158809CF4F3C", + "000102030405060708090A0B0C0D0E0F", + "6BC1BEE22E409F96E93D7E117393172A" + "AE2D8A571E03AC9C9EB76FAC45AF8E51", + "3AD77BB40D7A3660A89ECAF32466EF97" + "F5D3D58503B9699DE785895A96FDBAAF", + "7649ABAC8119B246CEE98E9B12E9197D" + "5086CB9B507219EE95DB113A917678B2", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "C8A64537A0B3A93FCDE3CDAD9F1CE58B", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "7789508D16918F03F53C52DAC54ED825", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "010C041999E03F36448624483E582D0E"); + + hash_test(af, "SHA-1", + "", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"); + + hash_test(af, "SHA-1", + "616263", "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + hash_test(af, "SHA-1", + "6162636462636465636465666465666765666768666768696768696A" + "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071", + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"); + + mac_test(af, "HMAC(SHA-1)", + "4869205468657265", + "B617318655057264E28BC0B6FB378C8EF146BE00", + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"); + + hash_test(af, "SHA-256", + "", + "E3B0C44298FC1C149AFBF4C8996FB924" + "27AE41E4649B934CA495991B7852B855"); + + hash_test(af, "SHA-256", + "616263", + "BA7816BF8F01CFEA414140DE5DAE2223" + "B00361A396177A9CB410FF61F20015AD"); + + hash_test(af, "SHA-256", + "6162636462636465636465666465666765666768666768696768696A" + "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071", + "248D6A61D20638B8E5C026930C3E6039" + "A33CE45964FF2167F6ECEDD419DB06C1"); + + mac_test(af, "HMAC(SHA-256)", + "4869205468657265", + "198A607EB44BFBC69903A0F1CF2BBDC5" + "BA0AA3F3D9AE3C1C7A3B1696A0B68CF7", + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B" + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"); + } + +} diff --git a/src/lib/selftest/selftest.h b/src/lib/selftest/selftest.h new file mode 100644 index 000000000..2ceadd0d4 --- /dev/null +++ b/src/lib/selftest/selftest.h @@ -0,0 +1,60 @@ +/* +* Startup Self Test +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SELF_TESTS_H__ +#define BOTAN_SELF_TESTS_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Run a set of self tests on some basic algorithms like AES and SHA-1 +* @param af an algorithm factory +* @throws Self_Test_Error if a failure occured +*/ +BOTAN_DLL void confirm_startup_self_tests(Algorithm_Factory& af); + +/** +* Run a set of self tests on some basic algorithms like AES and SHA-1 +* @param af an algorithm factory +* @returns false if a failure occured, otherwise true +*/ +BOTAN_DLL bool passes_self_tests(Algorithm_Factory& af); + +/** +* Run a set of algorithm KATs (known answer tests) +* @param algo_name the algorithm we are testing +* @param vars a set of input variables for this test, all + hex encoded. Keys used: "input", "output", "key", and "iv" +* @param af an algorithm factory +* @returns map from provider name to test result for that provider +*/ +BOTAN_DLL std::map +algorithm_kat(const SCAN_Name& algo_name, + const std::map& vars, + Algorithm_Factory& af); + +/** +* Run a set of algorithm KATs (known answer tests) +* @param algo_name the algorithm we are testing +* @param vars a set of input variables for this test, all + hex encoded. Keys used: "input", "output", "key", and "iv" +* @param af an algorithm factory +* @returns map from provider name to test result for that provider +*/ +BOTAN_DLL std::map +algorithm_kat_detailed(const SCAN_Name& algo_name, + const std::map& vars, + Algorithm_Factory& af); + +} + +#endif diff --git a/src/lib/simd/info.txt b/src/lib/simd/info.txt new file mode 100644 index 000000000..35620c940 --- /dev/null +++ b/src/lib/simd/info.txt @@ -0,0 +1,9 @@ +define SIMD_32 20131128 + + +simd_32.h + + + +simd_sse2|simd_altivec|simd_scalar + diff --git a/src/lib/simd/simd_32.h b/src/lib/simd/simd_32.h new file mode 100644 index 000000000..15f882fea --- /dev/null +++ b/src/lib/simd/simd_32.h @@ -0,0 +1,30 @@ +/* +* Lightweight wrappers for SIMD operations +* (C) 2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_32_H__ +#define BOTAN_SIMD_32_H__ + +#include + +#if defined(BOTAN_HAS_SIMD_SSE2) + #include + namespace Botan { typedef SIMD_SSE2 SIMD_32; } + +#elif defined(BOTAN_HAS_SIMD_ALTIVEC) + #include + namespace Botan { typedef SIMD_Altivec SIMD_32; } + +#elif defined(BOTAN_HAS_SIMD_SCALAR) + #include + namespace Botan { typedef SIMD_Scalar SIMD_32; } + +#else + #error "No SIMD module defined" + +#endif + +#endif diff --git a/src/lib/simd/simd_altivec/info.txt b/src/lib/simd/simd_altivec/info.txt new file mode 100644 index 000000000..19168a928 --- /dev/null +++ b/src/lib/simd/simd_altivec/info.txt @@ -0,0 +1,9 @@ +define SIMD_ALTIVEC 20131128 + +need_isa altivec + +load_on dep + + +simd_altivec.h + diff --git a/src/lib/simd/simd_altivec/simd_altivec.h b/src/lib/simd/simd_altivec/simd_altivec.h new file mode 100644 index 000000000..f675587bc --- /dev/null +++ b/src/lib/simd/simd_altivec/simd_altivec.h @@ -0,0 +1,218 @@ +/* +* Lightweight wrappers around AltiVec for 32-bit operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_ALTIVEC_H__ +#define BOTAN_SIMD_ALTIVEC_H__ + +#if defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) + +#include +#include + +#include +#undef vector +#undef bool + +namespace Botan { + +class SIMD_Altivec + { + public: + static bool enabled() { return CPUID::has_altivec(); } + + SIMD_Altivec(const u32bit B[4]) + { + reg = (__vector unsigned int){B[0], B[1], B[2], B[3]}; + } + + SIMD_Altivec(u32bit B0, u32bit B1, u32bit B2, u32bit B3) + { + reg = (__vector unsigned int){B0, B1, B2, B3}; + } + + SIMD_Altivec(u32bit B) + { + reg = (__vector unsigned int){B, B, B, B}; + } + + static SIMD_Altivec load_le(const void* in) + { + const u32bit* in_32 = static_cast(in); + + __vector unsigned int R0 = vec_ld(0, in_32); + __vector unsigned int R1 = vec_ld(12, in_32); + + __vector unsigned char perm = vec_lvsl(0, in_32); + + perm = vec_xor(perm, vec_splat_u8(3)); + + R0 = vec_perm(R0, R1, perm); + + return SIMD_Altivec(R0); + } + + static SIMD_Altivec load_be(const void* in) + { + const u32bit* in_32 = static_cast(in); + + __vector unsigned int R0 = vec_ld(0, in_32); + __vector unsigned int R1 = vec_ld(12, in_32); + + __vector unsigned char perm = vec_lvsl(0, in_32); + + R0 = vec_perm(R0, R1, perm); + + return SIMD_Altivec(R0); + } + + void store_le(byte out[]) const + { + __vector unsigned char perm = vec_lvsl(0, (u32bit*)0); + + perm = vec_xor(perm, vec_splat_u8(3)); + + union { + __vector unsigned int V; + u32bit R[4]; + } vec; + + vec.V = vec_perm(reg, reg, perm); + + Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + } + + void store_be(byte out[]) const + { + union { + __vector unsigned int V; + u32bit R[4]; + } vec; + + vec.V = reg; + + Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + } + + void rotate_left(size_t rot) + { + __vector unsigned int rot_vec = + (__vector unsigned int){rot, rot, rot, rot}; + + reg = vec_rl(reg, rot_vec); + } + + void rotate_right(size_t rot) + { + rotate_left(32 - rot); + } + + void operator+=(const SIMD_Altivec& other) + { + reg = vec_add(reg, other.reg); + } + + SIMD_Altivec operator+(const SIMD_Altivec& other) const + { + return vec_add(reg, other.reg); + } + + void operator-=(const SIMD_Altivec& other) + { + reg = vec_sub(reg, other.reg); + } + + SIMD_Altivec operator-(const SIMD_Altivec& other) const + { + return vec_sub(reg, other.reg); + } + + void operator^=(const SIMD_Altivec& other) + { + reg = vec_xor(reg, other.reg); + } + + SIMD_Altivec operator^(const SIMD_Altivec& other) const + { + return vec_xor(reg, other.reg); + } + + void operator|=(const SIMD_Altivec& other) + { + reg = vec_or(reg, other.reg); + } + + SIMD_Altivec operator&(const SIMD_Altivec& other) + { + return vec_and(reg, other.reg); + } + + void operator&=(const SIMD_Altivec& other) + { + reg = vec_and(reg, other.reg); + } + + SIMD_Altivec operator<<(size_t shift) const + { + __vector unsigned int shift_vec = + (__vector unsigned int){shift, shift, shift, shift}; + + return vec_sl(reg, shift_vec); + } + + SIMD_Altivec operator>>(size_t shift) const + { + __vector unsigned int shift_vec = + (__vector unsigned int){shift, shift, shift, shift}; + + return vec_sr(reg, shift_vec); + } + + SIMD_Altivec operator~() const + { + return vec_nor(reg, reg); + } + + SIMD_Altivec andc(const SIMD_Altivec& other) + { + // AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2 + return vec_andc(other.reg, reg); + } + + SIMD_Altivec bswap() const + { + __vector unsigned char perm = vec_lvsl(0, (u32bit*)0); + + perm = vec_xor(perm, vec_splat_u8(3)); + + return SIMD_Altivec(vec_perm(reg, reg, perm)); + } + + static void transpose(SIMD_Altivec& B0, SIMD_Altivec& B1, + SIMD_Altivec& B2, SIMD_Altivec& B3) + { + __vector unsigned int T0 = vec_mergeh(B0.reg, B2.reg); + __vector unsigned int T1 = vec_mergel(B0.reg, B2.reg); + __vector unsigned int T2 = vec_mergeh(B1.reg, B3.reg); + __vector unsigned int T3 = vec_mergel(B1.reg, B3.reg); + + B0.reg = vec_mergeh(T0, T2); + B1.reg = vec_mergel(T0, T2); + B2.reg = vec_mergeh(T1, T3); + B3.reg = vec_mergel(T1, T3); + } + + private: + SIMD_Altivec(__vector unsigned int input) { reg = input; } + + __vector unsigned int reg; + }; + +} + +#endif + +#endif diff --git a/src/lib/simd/simd_scalar/info.txt b/src/lib/simd/simd_scalar/info.txt new file mode 100644 index 000000000..26a9fbfee --- /dev/null +++ b/src/lib/simd/simd_scalar/info.txt @@ -0,0 +1,7 @@ +define SIMD_SCALAR 20131128 + +load_on dep + + +simd_scalar.h + diff --git a/src/lib/simd/simd_scalar/simd_scalar.h b/src/lib/simd/simd_scalar/simd_scalar.h new file mode 100644 index 000000000..55dd26d6f --- /dev/null +++ b/src/lib/simd/simd_scalar/simd_scalar.h @@ -0,0 +1,215 @@ +/* +* Scalar emulation of SIMD +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_SCALAR_H__ +#define BOTAN_SIMD_SCALAR_H__ + +#include +#include + +namespace Botan { + +/** +* Fake SIMD, using plain scalar operations +* Often still faster than iterative on superscalar machines +*/ +template +class SIMD_Scalar + { + public: + static bool enabled() { return true; } + + static size_t size() { return N; } + + SIMD_Scalar() { /* uninitialized */ } + + SIMD_Scalar(const T B[N]) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] = B[i]; + } + + SIMD_Scalar(T B) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] = B; + } + + static SIMD_Scalar load_le(const void* in) + { + SIMD_Scalar out; + const byte* in_b = static_cast(in); + + for(size_t i = 0; i != size(); ++i) + out.m_v[i] = Botan::load_le(in_b, i); + + return out; + } + + static SIMD_Scalar load_be(const void* in) + { + SIMD_Scalar out; + const byte* in_b = static_cast(in); + + for(size_t i = 0; i != size(); ++i) + out.m_v[i] = Botan::load_be(in_b, i); + + return out; + } + + void store_le(byte out[]) const + { + for(size_t i = 0; i != size(); ++i) + Botan::store_le(m_v[i], out + i*sizeof(T)); + } + + void store_be(byte out[]) const + { + for(size_t i = 0; i != size(); ++i) + Botan::store_be(m_v[i], out + i*sizeof(T)); + } + + void rotate_left(size_t rot) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] = Botan::rotate_left(m_v[i], rot); + } + + void rotate_right(size_t rot) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] = Botan::rotate_right(m_v[i], rot); + } + + void operator+=(const SIMD_Scalar& other) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] += other.m_v[i]; + } + + void operator-=(const SIMD_Scalar& other) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] -= other.m_v[i]; + } + + SIMD_Scalar operator+(const SIMD_Scalar& other) const + { + SIMD_Scalar out = *this; + out += other; + return out; + } + + SIMD_Scalar operator-(const SIMD_Scalar& other) const + { + SIMD_Scalar out = *this; + out -= other; + return out; + } + + void operator^=(const SIMD_Scalar& other) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] ^= other.m_v[i]; + } + + SIMD_Scalar operator^(const SIMD_Scalar& other) const + { + SIMD_Scalar out = *this; + out ^= other; + return out; + } + + void operator|=(const SIMD_Scalar& other) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] |= other.m_v[i]; + } + + void operator&=(const SIMD_Scalar& other) + { + for(size_t i = 0; i != size(); ++i) + m_v[i] &= other.m_v[i]; + } + + SIMD_Scalar operator&(const SIMD_Scalar& other) + { + SIMD_Scalar out = *this; + out &= other; + return out; + } + + SIMD_Scalar operator<<(size_t shift) const + { + SIMD_Scalar out = *this; + for(size_t i = 0; i != size(); ++i) + out.m_v[i] <<= shift; + return out; + } + + SIMD_Scalar operator>>(size_t shift) const + { + SIMD_Scalar out = *this; + for(size_t i = 0; i != size(); ++i) + out.m_v[i] >>= shift; + return out; + } + + SIMD_Scalar operator~() const + { + SIMD_Scalar out = *this; + for(size_t i = 0; i != size(); ++i) + out.m_v[i] = ~out.m_v[i]; + return out; + } + + // (~reg) & other + SIMD_Scalar andc(const SIMD_Scalar& other) + { + SIMD_Scalar out; + for(size_t i = 0; i != size(); ++i) + out.m_v[i] = (~m_v[i]) & other.m_v[i]; + return out; + } + + SIMD_Scalar bswap() const + { + SIMD_Scalar out; + for(size_t i = 0; i != size(); ++i) + out.m_v[i] = reverse_bytes(m_v[i]); + return out; + } + + static void transpose(SIMD_Scalar& B0, SIMD_Scalar& B1, + SIMD_Scalar& B2, SIMD_Scalar& B3) + { + static_assert(N == 4, "4x4 transpose"); + SIMD_Scalar T0({B0.m_v[0], B1.m_v[0], B2.m_v[0], B3.m_v[0]}); + SIMD_Scalar T1({B0.m_v[1], B1.m_v[1], B2.m_v[1], B3.m_v[1]}); + SIMD_Scalar T2({B0.m_v[2], B1.m_v[2], B2.m_v[2], B3.m_v[2]}); + SIMD_Scalar T3({B0.m_v[3], B1.m_v[3], B2.m_v[3], B3.m_v[3]}); + + B0 = T0; + B1 = T1; + B2 = T2; + B3 = T3; + } + + private: + SIMD_Scalar(std::initializer_list B) + { + size_t i = 0; + for(auto v = B.begin(); v != B.end(); ++v) + m_v[i++] = *v; + } + + T m_v[N]; + }; + +} + +#endif diff --git a/src/lib/simd/simd_sse2/info.txt b/src/lib/simd/simd_sse2/info.txt new file mode 100644 index 000000000..bd9e430cb --- /dev/null +++ b/src/lib/simd/simd_sse2/info.txt @@ -0,0 +1,9 @@ +define SIMD_SSE2 20131128 + +need_isa sse2 + +load_on dep + + +simd_sse2.h + diff --git a/src/lib/simd/simd_sse2/simd_sse2.h b/src/lib/simd/simd_sse2/simd_sse2.h new file mode 100644 index 000000000..6cbed1df8 --- /dev/null +++ b/src/lib/simd/simd_sse2/simd_sse2.h @@ -0,0 +1,169 @@ +/* +* Lightweight wrappers for SSE2 intrinsics for 32-bit operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_SSE_H__ +#define BOTAN_SIMD_SSE_H__ + +#if defined(BOTAN_TARGET_SUPPORTS_SSE2) + +#include +#include + +namespace Botan { + +class SIMD_SSE2 + { + public: + static bool enabled() { return CPUID::has_sse2(); } + + SIMD_SSE2(const u32bit B[4]) + { + reg = _mm_loadu_si128(reinterpret_cast(B)); + } + + SIMD_SSE2(u32bit B0, u32bit B1, u32bit B2, u32bit B3) + { + reg = _mm_set_epi32(B0, B1, B2, B3); + } + + SIMD_SSE2(u32bit B) + { + reg = _mm_set1_epi32(B); + } + + static SIMD_SSE2 load_le(const void* in) + { + return _mm_loadu_si128(reinterpret_cast(in)); + } + + static SIMD_SSE2 load_be(const void* in) + { + return load_le(in).bswap(); + } + + void store_le(byte out[]) const + { + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), reg); + } + + void store_be(byte out[]) const + { + bswap().store_le(out); + } + + void rotate_left(size_t rot) + { + reg = _mm_or_si128(_mm_slli_epi32(reg, static_cast(rot)), + _mm_srli_epi32(reg, static_cast(32-rot))); + } + + void rotate_right(size_t rot) + { + rotate_left(32 - rot); + } + + void operator+=(const SIMD_SSE2& other) + { + reg = _mm_add_epi32(reg, other.reg); + } + + SIMD_SSE2 operator+(const SIMD_SSE2& other) const + { + return _mm_add_epi32(reg, other.reg); + } + + void operator-=(const SIMD_SSE2& other) + { + reg = _mm_sub_epi32(reg, other.reg); + } + + SIMD_SSE2 operator-(const SIMD_SSE2& other) const + { + return _mm_sub_epi32(reg, other.reg); + } + + void operator^=(const SIMD_SSE2& other) + { + reg = _mm_xor_si128(reg, other.reg); + } + + SIMD_SSE2 operator^(const SIMD_SSE2& other) const + { + return _mm_xor_si128(reg, other.reg); + } + + void operator|=(const SIMD_SSE2& other) + { + reg = _mm_or_si128(reg, other.reg); + } + + SIMD_SSE2 operator&(const SIMD_SSE2& other) + { + return _mm_and_si128(reg, other.reg); + } + + void operator&=(const SIMD_SSE2& other) + { + reg = _mm_and_si128(reg, other.reg); + } + + SIMD_SSE2 operator<<(size_t shift) const + { + return _mm_slli_epi32(reg, static_cast(shift)); + } + + SIMD_SSE2 operator>>(size_t shift) const + { + return _mm_srli_epi32(reg, static_cast(shift)); + } + + SIMD_SSE2 operator~() const + { + return _mm_xor_si128(reg, _mm_set1_epi32(0xFFFFFFFF)); + } + + // (~reg) & other + SIMD_SSE2 andc(const SIMD_SSE2& other) + { + return _mm_andnot_si128(reg, other.reg); + } + + SIMD_SSE2 bswap() const + { + __m128i T = reg; + + T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + + return _mm_or_si128(_mm_srli_epi16(T, 8), + _mm_slli_epi16(T, 8)); + } + + static void transpose(SIMD_SSE2& B0, SIMD_SSE2& B1, + SIMD_SSE2& B2, SIMD_SSE2& B3) + { + __m128i T0 = _mm_unpacklo_epi32(B0.reg, B1.reg); + __m128i T1 = _mm_unpacklo_epi32(B2.reg, B3.reg); + __m128i T2 = _mm_unpackhi_epi32(B0.reg, B1.reg); + __m128i T3 = _mm_unpackhi_epi32(B2.reg, B3.reg); + B0.reg = _mm_unpacklo_epi64(T0, T1); + B1.reg = _mm_unpackhi_epi64(T0, T1); + B2.reg = _mm_unpacklo_epi64(T2, T3); + B3.reg = _mm_unpackhi_epi64(T2, T3); + } + + private: + SIMD_SSE2(__m128i in) { reg = in; } + + __m128i reg; + }; + +} + +#endif + +#endif diff --git a/src/lib/stream/ctr/ctr.cpp b/src/lib/stream/ctr/ctr.cpp new file mode 100644 index 000000000..87ec86c65 --- /dev/null +++ b/src/lib/stream/ctr/ctr.cpp @@ -0,0 +1,134 @@ +/* +* Counter mode +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* CTR-BE Constructor +*/ + +CTR_BE::CTR_BE(BlockCipher* ciph) : + permutation(ciph), + counter(256 * permutation->block_size()), + buffer(counter.size()), + position(0) + { + } + +/* +* CTR_BE Destructor +*/ +CTR_BE::~CTR_BE() + { + delete permutation; + } + +/* +* Zeroize +*/ +void CTR_BE::clear() + { + permutation->clear(); + zeroise(buffer); + zeroise(counter); + position = 0; + } + +/* +* Set the key +*/ +void CTR_BE::key_schedule(const byte key[], size_t key_len) + { + permutation->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +/* +* Return the name of this type +*/ +std::string CTR_BE::name() const + { + return ("CTR-BE(" + permutation->name() + ")"); + } + +/* +* CTR-BE Encryption/Decryption +*/ +void CTR_BE::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + increment_counter(); + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Set CTR-BE IV +*/ +void CTR_BE::set_iv(const byte iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + const size_t bs = permutation->block_size(); + + zeroise(counter); + + buffer_insert(counter, 0, iv, iv_len); + + /* + * Set counter blocks to IV, IV + 1, ... IV + 255 + */ + for(size_t i = 1; i != 256; ++i) + { + buffer_insert(counter, i*bs, &counter[(i-1)*bs], bs); + + for(size_t j = 0; j != bs; ++j) + if(++counter[i*bs + (bs - 1 - j)]) + break; + } + + permutation->encrypt_n(&counter[0], &buffer[0], 256); + position = 0; + } + +/* +* Increment the counter and update the buffer +*/ +void CTR_BE::increment_counter() + { + const size_t bs = permutation->block_size(); + + /* + * Each counter value always needs to be incremented by 256, + * so we don't touch the lowest byte and instead treat it as + * an increment of one starting with the next byte. + */ + for(size_t i = 0; i != 256; ++i) + { + for(size_t j = 1; j != bs; ++j) + if(++counter[i*bs + (bs - 1 - j)]) + break; + } + + permutation->encrypt_n(&counter[0], &buffer[0], 256); + + position = 0; + } + +} diff --git a/src/lib/stream/ctr/ctr.h b/src/lib/stream/ctr/ctr.h new file mode 100644 index 000000000..84cf9ed5d --- /dev/null +++ b/src/lib/stream/ctr/ctr.h @@ -0,0 +1,61 @@ +/* +* CTR-BE Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CTR_BE_H__ +#define BOTAN_CTR_BE_H__ + +#include +#include + +namespace Botan { + +/** +* CTR-BE (Counter mode, big-endian) +*/ +class BOTAN_DLL CTR_BE : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void set_iv(const byte iv[], size_t iv_len); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len <= permutation->block_size()); } + + Key_Length_Specification key_spec() const + { + return permutation->key_spec(); + } + + std::string name() const; + + CTR_BE* clone() const + { return new CTR_BE(permutation->clone()); } + + void clear(); + + /** + * @param cipher the underlying block cipher to use + */ + CTR_BE(BlockCipher* cipher); + + CTR_BE(const CTR_BE&) = delete; + CTR_BE& operator=(const CTR_BE&) = delete; + + ~CTR_BE(); + private: + void key_schedule(const byte key[], size_t key_len); + void increment_counter(); + + BlockCipher* permutation; + secure_vector counter, buffer; + size_t position; + }; + +} + +#endif diff --git a/src/lib/stream/ctr/info.txt b/src/lib/stream/ctr/info.txt new file mode 100644 index 000000000..84d90a76f --- /dev/null +++ b/src/lib/stream/ctr/info.txt @@ -0,0 +1,6 @@ +define CTR_BE 20131128 + + +block +stream + diff --git a/src/lib/stream/info.txt b/src/lib/stream/info.txt new file mode 100644 index 000000000..faa2db215 --- /dev/null +++ b/src/lib/stream/info.txt @@ -0,0 +1,5 @@ +define STREAM_CIPHER 20131128 + + +algo_base + diff --git a/src/lib/stream/ofb/info.txt b/src/lib/stream/ofb/info.txt new file mode 100644 index 000000000..11b6bfb27 --- /dev/null +++ b/src/lib/stream/ofb/info.txt @@ -0,0 +1,6 @@ +define OFB 20131128 + + +block +stream + diff --git a/src/lib/stream/ofb/ofb.cpp b/src/lib/stream/ofb/ofb.cpp new file mode 100644 index 000000000..1137a58af --- /dev/null +++ b/src/lib/stream/ofb/ofb.cpp @@ -0,0 +1,93 @@ +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* OFB Constructor +*/ +OFB::OFB(BlockCipher* ciph) : permutation(ciph) + { + position = 0; + buffer.resize(permutation->block_size()); + } + +/* +* OFB Destructor +*/ +OFB::~OFB() + { + delete permutation; + } + +/* +* Zeroize +*/ +void OFB::clear() + { + permutation->clear(); + zeroise(buffer); + position = 0; + } + +/* +* Set the key +*/ +void OFB::key_schedule(const byte key[], size_t key_len) + { + permutation->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +/* +* Return the name of this type +*/ +std::string OFB::name() const + { + return ("OFB(" + permutation->name() + ")"); + } + +/* +* CTR-BE Encryption/Decryption +*/ +void OFB::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + permutation->encrypt(buffer); + position = 0; + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Set CTR-BE IV +*/ +void OFB::set_iv(const byte iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + zeroise(buffer); + buffer_insert(buffer, 0, iv, iv_len); + + permutation->encrypt(buffer); + position = 0; + } + +} diff --git a/src/lib/stream/ofb/ofb.h b/src/lib/stream/ofb/ofb.h new file mode 100644 index 000000000..9d4fd882f --- /dev/null +++ b/src/lib/stream/ofb/ofb.h @@ -0,0 +1,56 @@ +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OUTPUT_FEEDBACK_MODE_H__ +#define BOTAN_OUTPUT_FEEDBACK_MODE_H__ + +#include +#include + +namespace Botan { + +/** +* Output Feedback Mode +*/ +class BOTAN_DLL OFB : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void set_iv(const byte iv[], size_t iv_len); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len <= permutation->block_size()); } + + Key_Length_Specification key_spec() const + { + return permutation->key_spec(); + } + + std::string name() const; + + OFB* clone() const + { return new OFB(permutation->clone()); } + + void clear(); + + /** + * @param cipher the underlying block cipher to use + */ + OFB(BlockCipher* cipher); + ~OFB(); + private: + void key_schedule(const byte key[], size_t key_len); + + BlockCipher* permutation; + secure_vector buffer; + size_t position; + }; + +} + +#endif diff --git a/src/lib/stream/rc4/info.txt b/src/lib/stream/rc4/info.txt new file mode 100644 index 000000000..f61b8a4cc --- /dev/null +++ b/src/lib/stream/rc4/info.txt @@ -0,0 +1 @@ +define RC4 20131128 diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp new file mode 100644 index 000000000..df6976235 --- /dev/null +++ b/src/lib/stream/rc4/rc4.cpp @@ -0,0 +1,109 @@ +/* +* RC4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Combine cipher stream with message +*/ +void RC4::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + generate(); + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Generate cipher stream +*/ +void RC4::generate() + { + byte SX, SY; + for(size_t i = 0; i != buffer.size(); i += 4) + { + SX = state[X+1]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+1] = SY; state[Y] = SX; + buffer[i] = state[(SX + SY) % 256]; + + SX = state[X+2]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+2] = SY; state[Y] = SX; + buffer[i+1] = state[(SX + SY) % 256]; + + SX = state[X+3]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+3] = SY; state[Y] = SX; + buffer[i+2] = state[(SX + SY) % 256]; + + X = (X + 4) % 256; + SX = state[X]; Y = (Y + SX) % 256; SY = state[Y]; + state[X] = SY; state[Y] = SX; + buffer[i+3] = state[(SX + SY) % 256]; + } + position = 0; + } + +/* +* RC4 Key Schedule +*/ +void RC4::key_schedule(const byte key[], size_t length) + { + state.resize(256); + buffer.resize(round_up(DEFAULT_BUFFERSIZE, 4)); + + position = X = Y = 0; + + for(size_t i = 0; i != 256; ++i) + state[i] = static_cast(i); + + for(size_t i = 0, state_index = 0; i != 256; ++i) + { + state_index = (state_index + key[i % length] + state[i]) % 256; + std::swap(state[i], state[state_index]); + } + + for(size_t i = 0; i <= SKIP; i += buffer.size()) + generate(); + + position += (SKIP % buffer.size()); + } + +/* +* Return the name of this type +*/ +std::string RC4::name() const + { + if(SKIP == 0) return "RC4"; + if(SKIP == 256) return "MARK-4"; + else return "RC4_skip(" + std::to_string(SKIP) + ")"; + } + +/* +* Clear memory of sensitive data +*/ +void RC4::clear() + { + zap(state); + zap(buffer); + position = X = Y = 0; + } + +/* +* RC4 Constructor +*/ +RC4::RC4(size_t s) : SKIP(s) {} + +} diff --git a/src/lib/stream/rc4/rc4.h b/src/lib/stream/rc4/rc4.h new file mode 100644 index 000000000..c23f8c853 --- /dev/null +++ b/src/lib/stream/rc4/rc4.h @@ -0,0 +1,55 @@ +/* +* RC4 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RC4_H__ +#define BOTAN_RC4_H__ + +#include +#include + +namespace Botan { + +/** +* RC4 stream cipher +*/ +class BOTAN_DLL RC4 : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void clear(); + std::string name() const; + + StreamCipher* clone() const { return new RC4(SKIP); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(1, 256); + } + + /** + * @param skip skip this many initial bytes in the keystream + */ + RC4(size_t skip = 0); + + ~RC4() { clear(); } + private: + void key_schedule(const byte[], size_t); + void generate(); + + const size_t SKIP; + + byte X, Y; + secure_vector state; + + secure_vector buffer; + size_t position; + }; + +} + +#endif diff --git a/src/lib/stream/salsa20/info.txt b/src/lib/stream/salsa20/info.txt new file mode 100644 index 000000000..10f9a8cb2 --- /dev/null +++ b/src/lib/stream/salsa20/info.txt @@ -0,0 +1 @@ +define SALSA20 20131128 diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp new file mode 100644 index 000000000..d8db69ae6 --- /dev/null +++ b/src/lib/stream/salsa20/salsa20.cpp @@ -0,0 +1,243 @@ +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4) \ + do { \ + x2 ^= rotate_left(x1 + x4, 7); \ + x3 ^= rotate_left(x2 + x1, 9); \ + x4 ^= rotate_left(x3 + x2, 13); \ + x1 ^= rotate_left(x4 + x3, 18); \ + } while(0) + +/* +* Generate HSalsa20 cipher stream (for XSalsa20 IV setup) +*/ +void hsalsa20(u32bit output[8], const u32bit input[16]) + { + u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != 10; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + output[0] = x00; + output[1] = x05; + output[2] = x10; + output[3] = x15; + output[4] = x06; + output[5] = x07; + output[6] = x08; + output[7] = x09; + } + +/* +* Generate Salsa20 cipher stream +*/ +void salsa20(byte output[64], const u32bit input[16]) + { + u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != 10; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + store_le(x00 + input[ 0], output + 4 * 0); + store_le(x01 + input[ 1], output + 4 * 1); + store_le(x02 + input[ 2], output + 4 * 2); + store_le(x03 + input[ 3], output + 4 * 3); + store_le(x04 + input[ 4], output + 4 * 4); + store_le(x05 + input[ 5], output + 4 * 5); + store_le(x06 + input[ 6], output + 4 * 6); + store_le(x07 + input[ 7], output + 4 * 7); + store_le(x08 + input[ 8], output + 4 * 8); + store_le(x09 + input[ 9], output + 4 * 9); + store_le(x10 + input[10], output + 4 * 10); + store_le(x11 + input[11], output + 4 * 11); + store_le(x12 + input[12], output + 4 * 12); + store_le(x13 + input[13], output + 4 * 13); + store_le(x14 + input[14], output + 4 * 14); + store_le(x15 + input[15], output + 4 * 15); + } + +} + +/* +* Combine cipher stream with message +*/ +void Salsa20::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + salsa20(&buffer[0], &state[0]); + + ++state[8]; + if(!state[8]) // if overflow in state[8] + ++state[9]; // carry to state[9] + + position = 0; + } + + xor_buf(out, in, &buffer[position], length); + + position += length; + } + +/* +* Salsa20 Key Schedule +*/ +void Salsa20::key_schedule(const byte key[], size_t length) + { + static const u32bit TAU[] = + { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; + + static const u32bit SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + state.resize(16); + buffer.resize(64); + + if(length == 16) + { + state[0] = TAU[0]; + state[1] = load_le(key, 0); + state[2] = load_le(key, 1); + state[3] = load_le(key, 2); + state[4] = load_le(key, 3); + state[5] = TAU[1]; + state[10] = TAU[2]; + state[11] = load_le(key, 0); + state[12] = load_le(key, 1); + state[13] = load_le(key, 2); + state[14] = load_le(key, 3); + state[15] = TAU[3]; + } + else if(length == 32) + { + state[0] = SIGMA[0]; + state[1] = load_le(key, 0); + state[2] = load_le(key, 1); + state[3] = load_le(key, 2); + state[4] = load_le(key, 3); + state[5] = SIGMA[1]; + state[10] = SIGMA[2]; + state[11] = load_le(key, 4); + state[12] = load_le(key, 5); + state[13] = load_le(key, 6); + state[14] = load_le(key, 7); + state[15] = SIGMA[3]; + } + + position = 0; + + const byte ZERO[8] = { 0 }; + set_iv(ZERO, sizeof(ZERO)); + } + +/* +* Return the name of this type +*/ +void Salsa20::set_iv(const byte iv[], size_t length) + { + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + if(length == 8) + { + // Salsa20 + state[6] = load_le(iv, 0); + state[7] = load_le(iv, 1); + } + else + { + // XSalsa20 + state[6] = load_le(iv, 0); + state[7] = load_le(iv, 1); + state[8] = load_le(iv, 2); + state[9] = load_le(iv, 3); + + secure_vector hsalsa(8); + hsalsa20(&hsalsa[0], &state[0]); + + state[ 1] = hsalsa[0]; + state[ 2] = hsalsa[1]; + state[ 3] = hsalsa[2]; + state[ 4] = hsalsa[3]; + state[ 6] = load_le(iv, 4); + state[ 7] = load_le(iv, 5); + state[11] = hsalsa[4]; + state[12] = hsalsa[5]; + state[13] = hsalsa[6]; + state[14] = hsalsa[7]; + } + + state[8] = 0; + state[9] = 0; + + salsa20(&buffer[0], &state[0]); + ++state[8]; + if(!state[8]) // if overflow in state[8] + ++state[9]; // carry to state[9] + + position = 0; + } + +/* +* Return the name of this type +*/ +std::string Salsa20::name() const + { + return "Salsa20"; + } + +/* +* Clear memory of sensitive data +*/ +void Salsa20::clear() + { + zap(state); + zap(buffer); + position = 0; + } + +} diff --git a/src/lib/stream/salsa20/salsa20.h b/src/lib/stream/salsa20/salsa20.h new file mode 100644 index 000000000..b68bb979e --- /dev/null +++ b/src/lib/stream/salsa20/salsa20.h @@ -0,0 +1,46 @@ +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SALSA20_H__ +#define BOTAN_SALSA20_H__ + +#include + +namespace Botan { + +/** +* DJB's Salsa20 (and XSalsa20) +*/ +class BOTAN_DLL Salsa20 : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void set_iv(const byte iv[], size_t iv_len); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == 8 || iv_len == 24); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(16, 32, 16); + } + + void clear(); + std::string name() const; + StreamCipher* clone() const { return new Salsa20; } + private: + void key_schedule(const byte key[], size_t key_len); + + secure_vector state; + secure_vector buffer; + size_t position; + }; + +} + +#endif diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp new file mode 100644 index 000000000..7dbd3e2e3 --- /dev/null +++ b/src/lib/stream/stream_cipher.cpp @@ -0,0 +1,24 @@ +/* +* Stream Cipher +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +void StreamCipher::set_iv(const byte[], size_t iv_len) + { + if(iv_len) + throw Invalid_Argument("The stream cipher " + name() + + " does not support resyncronization"); + } + +bool StreamCipher::valid_iv_length(size_t iv_len) const + { + return (iv_len == 0); + } + +} diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h new file mode 100644 index 000000000..f3d3999f0 --- /dev/null +++ b/src/lib/stream/stream_cipher.h @@ -0,0 +1,70 @@ +/* +* Stream Cipher +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_STREAM_CIPHER_H__ +#define BOTAN_STREAM_CIPHER_H__ + +#include + +namespace Botan { + +/** +* Base class for all stream ciphers +*/ +class BOTAN_DLL StreamCipher : public SymmetricAlgorithm + { + public: + /** + * Encrypt or decrypt a message + * @param in the plaintext + * @param out the byte array to hold the output, i.e. the ciphertext + * @param len the length of both in and out in bytes + */ + virtual void cipher(const byte in[], byte out[], size_t len) = 0; + + /** + * Encrypt or decrypt a message + * @param buf the plaintext / ciphertext + * @param len the length of buf in bytes + */ + void cipher1(byte buf[], size_t len) + { cipher(buf, buf, len); } + + template + void encipher(std::vector& inout) + { cipher(&inout[0], &inout[0], inout.size()); } + + template + void encrypt(std::vector& inout) + { cipher(&inout[0], &inout[0], inout.size()); } + + template + void decrypt(std::vector& inout) + { cipher(&inout[0], &inout[0], inout.size()); } + + /** + * Resync the cipher using the IV + * @param iv the initialization vector + * @param iv_len the length of the IV in bytes + */ + virtual void set_iv(const byte iv[], size_t iv_len); + + /** + * @param iv_len the length of the IV in bytes + * @return if the length is valid for this algorithm + */ + virtual bool valid_iv_length(size_t iv_len) const; + + /** + * Get a new object representing the same algorithm as *this + */ + virtual StreamCipher* clone() const = 0; + }; + +} + +#endif diff --git a/src/lib/tls/info.txt b/src/lib/tls/info.txt new file mode 100644 index 000000000..adae12cb2 --- /dev/null +++ b/src/lib/tls/info.txt @@ -0,0 +1,90 @@ +define TLS 20131128 + +load_on auto + + +tls_alert.h +tls_blocking.h +tls_channel.h +tls_ciphersuite.h +tls_client.h +tls_exceptn.h +tls_handshake_msg.h +tls_magic.h +tls_server_info.h +tls_policy.h +tls_server.h +tls_session.h +tls_session_manager.h +tls_version.h + + + +tls_extensions.h +tls_handshake_hash.h +tls_handshake_io.h +tls_handshake_state.h +tls_heartbeats.h +tls_messages.h +tls_reader.h +tls_record.h +tls_seq_numbers.h +tls_session_key.h + + + +msg_cert_req.cpp +msg_cert_verify.cpp +msg_certificate.cpp +msg_client_hello.cpp +msg_client_kex.cpp +msg_finished.cpp +msg_hello_verify.cpp +msg_next_protocol.cpp +msg_server_hello.cpp +msg_server_kex.cpp +msg_session_ticket.cpp +tls_alert.cpp +tls_blocking.cpp +tls_channel.cpp +tls_ciphersuite.cpp +tls_client.cpp +tls_extensions.cpp +tls_handshake_hash.cpp +tls_handshake_io.cpp +tls_handshake_state.cpp +tls_heartbeats.cpp +tls_policy.cpp +tls_server.cpp +tls_session.cpp +tls_session_key.cpp +tls_session_manager_memory.cpp +tls_suite_info.cpp +tls_record.cpp +tls_version.cpp + + + +aead +aes +asn1 +cbc +credentials +cryptobox_psk +dh +ecdh +eme_pkcs +emsa3 +hmac +kdf2 +md5 +prf_ssl3 +prf_tls +rng +rsa +sha1 +sha2_32 +srp6 +ssl3mac +x509 + diff --git a/src/lib/tls/msg_cert_req.cpp b/src/lib/tls/msg_cert_req.cpp new file mode 100644 index 000000000..23d59c6d4 --- /dev/null +++ b/src/lib/tls/msg_cert_req.cpp @@ -0,0 +1,163 @@ +/* +* Certificate Request Message +* (C) 2004-2006,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +std::string cert_type_code_to_name(byte code) + { + switch(code) + { + case 1: + return "RSA"; + case 2: + return "DSA"; + case 64: + return "ECDSA"; + default: + return ""; // DH or something else + } + } + +byte cert_type_name_to_code(const std::string& name) + { + if(name == "RSA") + return 1; + if(name == "DSA") + return 2; + if(name == "ECDSA") + return 64; + + throw Invalid_Argument("Unknown cert type " + name); + } + +} + +/** +* Create a new Certificate Request message +*/ +Certificate_Req::Certificate_Req(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + const std::vector& ca_certs, + Protocol_Version version) : + m_names(ca_certs), + m_cert_key_types({ "RSA", "DSA", "ECDSA" }) + { + if(version.supports_negotiable_signature_algorithms()) + { + std::vector hashes = policy.allowed_signature_hashes(); + std::vector sigs = policy.allowed_signature_methods(); + + for(size_t i = 0; i != hashes.size(); ++i) + for(size_t j = 0; j != sigs.size(); ++j) + m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j])); + } + + hash.update(io.send(*this)); + } + +/** +* Deserialize a Certificate Request message +*/ +Certificate_Req::Certificate_Req(const std::vector& buf, + Protocol_Version version) + { + if(buf.size() < 4) + throw Decoding_Error("Certificate_Req: Bad certificate request"); + + TLS_Data_Reader reader(buf); + + std::vector cert_type_codes = reader.get_range_vector(1, 1, 255); + + for(size_t i = 0; i != cert_type_codes.size(); ++i) + { + const std::string cert_type_name = cert_type_code_to_name(cert_type_codes[i]); + + if(cert_type_name == "") // something we don't know + continue; + + m_cert_key_types.push_back(cert_type_name); + } + + if(version.supports_negotiable_signature_algorithms()) + { + std::vector sig_hash_algs = reader.get_range_vector(2, 2, 65534); + + if(sig_hash_algs.size() % 2 != 0) + throw Decoding_Error("Bad length for signature IDs in certificate request"); + + for(size_t i = 0; i != sig_hash_algs.size(); i += 2) + { + std::string hash = Signature_Algorithms::hash_algo_name(sig_hash_algs[i]); + std::string sig = Signature_Algorithms::sig_algo_name(sig_hash_algs[i+1]); + m_supported_algos.push_back(std::make_pair(hash, sig)); + } + } + + const u16bit purported_size = reader.get_u16bit(); + + if(reader.remaining_bytes() != purported_size) + throw Decoding_Error("Inconsistent length in certificate request"); + + while(reader.has_remaining()) + { + std::vector name_bits = reader.get_range_vector(2, 0, 65535); + + BER_Decoder decoder(&name_bits[0], name_bits.size()); + X509_DN name; + decoder.decode(name); + m_names.push_back(name); + } + } + +/** +* Serialize a Certificate Request message +*/ +std::vector Certificate_Req::serialize() const + { + std::vector buf; + + std::vector cert_types; + + for(size_t i = 0; i != m_cert_key_types.size(); ++i) + cert_types.push_back(cert_type_name_to_code(m_cert_key_types[i])); + + append_tls_length_value(buf, cert_types, 1); + + if(!m_supported_algos.empty()) + buf += Signature_Algorithms(m_supported_algos).serialize(); + + std::vector encoded_names; + + for(size_t i = 0; i != m_names.size(); ++i) + { + DER_Encoder encoder; + encoder.encode(m_names[i]); + + append_tls_length_value(encoded_names, encoder.get_contents(), 2); + } + + append_tls_length_value(buf, encoded_names, 2); + + return buf; + } + +} + +} diff --git a/src/lib/tls/msg_cert_verify.cpp b/src/lib/tls/msg_cert_verify.cpp new file mode 100644 index 000000000..436b84c24 --- /dev/null +++ b/src/lib/tls/msg_cert_verify.cpp @@ -0,0 +1,117 @@ +/* +* Certificate Verify Message +* (C) 2004,2006,2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/* +* Create a new Certificate Verify message +*/ +Certificate_Verify::Certificate_Verify(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + RandomNumberGenerator& rng, + const Private_Key* priv_key) + { + BOTAN_ASSERT_NONNULL(priv_key); + + std::pair format = + state.choose_sig_format(*priv_key, m_hash_algo, m_sig_algo, true, policy); + + PK_Signer signer(*priv_key, format.first, format.second); + + if(state.version() == Protocol_Version::SSL_V3) + { + secure_vector md5_sha = state.hash().final_ssl3( + state.session_keys().master_secret()); + + if(priv_key->algo_name() == "DSA") + m_signature = signer.sign_message(&md5_sha[16], md5_sha.size()-16, rng); + else + m_signature = signer.sign_message(md5_sha, rng); + } + else + { + m_signature = signer.sign_message(state.hash().get_contents(), rng); + } + + state.hash().update(io.send(*this)); + } + +/* +* Deserialize a Certificate Verify message +*/ +Certificate_Verify::Certificate_Verify(const std::vector& buf, + Protocol_Version version) + { + TLS_Data_Reader reader(buf); + + if(version.supports_negotiable_signature_algorithms()) + { + m_hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte()); + m_sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte()); + } + + m_signature = reader.get_range(2, 0, 65535); + } + +/* +* Serialize a Certificate Verify message +*/ +std::vector Certificate_Verify::serialize() const + { + std::vector buf; + + if(m_hash_algo != "" && m_sig_algo != "") + { + buf.push_back(Signature_Algorithms::hash_algo_code(m_hash_algo)); + buf.push_back(Signature_Algorithms::sig_algo_code(m_sig_algo)); + } + + const u16bit sig_len = m_signature.size(); + buf.push_back(get_byte(0, sig_len)); + buf.push_back(get_byte(1, sig_len)); + buf += m_signature; + + return buf; + } + +/* +* Verify a Certificate Verify message +*/ +bool Certificate_Verify::verify(const X509_Certificate& cert, + const Handshake_State& state) const + { + std::unique_ptr key(cert.subject_public_key()); + + std::pair format = + state.understand_sig_format(*key.get(), m_hash_algo, m_sig_algo, true); + + PK_Verifier verifier(*key, format.first, format.second); + + if(state.version() == Protocol_Version::SSL_V3) + { + secure_vector md5_sha = state.hash().final_ssl3( + state.session_keys().master_secret()); + + return verifier.verify_message(&md5_sha[16], md5_sha.size()-16, + &m_signature[0], m_signature.size()); + } + + return verifier.verify_message(state.hash().get_contents(), m_signature); + } + +} + +} diff --git a/src/lib/tls/msg_certificate.cpp b/src/lib/tls/msg_certificate.cpp new file mode 100644 index 000000000..417ad34ce --- /dev/null +++ b/src/lib/tls/msg_certificate.cpp @@ -0,0 +1,88 @@ +/* +* Certificate Message +* (C) 2004-2006,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Create a new Certificate message +*/ +Certificate::Certificate(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& cert_list) : + m_certs(cert_list) + { + hash.update(io.send(*this)); + } + +/** +* Deserialize a Certificate message +*/ +Certificate::Certificate(const std::vector& buf) + { + if(buf.size() < 3) + throw Decoding_Error("Certificate: Message malformed"); + + const size_t total_size = make_u32bit(0, buf[0], buf[1], buf[2]); + + if(total_size != buf.size() - 3) + throw Decoding_Error("Certificate: Message malformed"); + + const byte* certs = &buf[3]; + + while(size_t remaining_bytes = &buf[buf.size()] - certs) + { + if(remaining_bytes < 3) + throw Decoding_Error("Certificate: Message malformed"); + + const size_t cert_size = make_u32bit(0, certs[0], certs[1], certs[2]); + + if(remaining_bytes < (3 + cert_size)) + throw Decoding_Error("Certificate: Message malformed"); + + DataSource_Memory cert_buf(&certs[3], cert_size); + m_certs.push_back(X509_Certificate(cert_buf)); + + certs += cert_size + 3; + } + } + +/** +* Serialize a Certificate message +*/ +std::vector Certificate::serialize() const + { + std::vector buf(3); + + for(size_t i = 0; i != m_certs.size(); ++i) + { + std::vector raw_cert = m_certs[i].BER_encode(); + const size_t cert_size = raw_cert.size(); + for(size_t i = 0; i != 3; ++i) + buf.push_back(get_byte(i+1, cert_size)); + buf += raw_cert; + } + + const size_t buf_size = buf.size() - 3; + for(size_t i = 0; i != 3; ++i) + buf[i] = get_byte(i+1, buf_size); + + return buf; + } + +} + +} diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp new file mode 100644 index 000000000..0d91af472 --- /dev/null +++ b/src/lib/tls/msg_client_hello.cpp @@ -0,0 +1,287 @@ +/* +* TLS Hello Request and Client Hello Messages +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +enum { + TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF +}; + +std::vector make_hello_random(RandomNumberGenerator& rng) + { + std::vector buf(32); + + const u32bit time32 = static_cast( + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); + + store_be(time32, &buf[0]); + rng.randomize(&buf[4], buf.size() - 4); + return buf; + } + +/* +* Create a new Hello Request message +*/ +Hello_Request::Hello_Request(Handshake_IO& io) + { + io.send(*this); + } + +/* +* Deserialize a Hello Request message +*/ +Hello_Request::Hello_Request(const std::vector& buf) + { + if(buf.size()) + throw Decoding_Error("Bad Hello_Request, has non-zero size"); + } + +/* +* Serialize a Hello Request message +*/ +std::vector Hello_Request::serialize() const + { + return std::vector(); + } + +/* +* Create a new Client Hello message +*/ +Client_Hello::Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + Protocol_Version version, + const Policy& policy, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + bool next_protocol, + const std::string& hostname, + const std::string& srp_identifier) : + m_version(version), + m_random(make_hello_random(rng)), + m_suites(policy.ciphersuite_list(m_version, (srp_identifier != ""))), + m_comp_methods(policy.compression()) + { + m_extensions.add(new Renegotiation_Extension(reneg_info)); + m_extensions.add(new SRP_Identifier(srp_identifier)); + m_extensions.add(new Server_Name_Indicator(hostname)); + m_extensions.add(new Session_Ticket()); + m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); + + if(policy.negotiate_heartbeat_support()) + m_extensions.add(new Heartbeat_Support_Indicator(true)); + + if(m_version.supports_negotiable_signature_algorithms()) + m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), + policy.allowed_signature_methods())); + + if(reneg_info.empty() && next_protocol) + m_extensions.add(new Next_Protocol_Notification()); + + hash.update(io.send(*this)); + } + +/* +* Create a new Client Hello message (session resumption case) +*/ +Client_Hello::Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Session& session, + bool next_protocol) : + m_version(session.version()), + m_session_id(session.session_id()), + m_random(make_hello_random(rng)), + m_suites(policy.ciphersuite_list(m_version, (session.srp_identifier() != ""))), + m_comp_methods(policy.compression()) + { + if(!value_exists(m_suites, session.ciphersuite_code())) + m_suites.push_back(session.ciphersuite_code()); + + if(!value_exists(m_comp_methods, session.compression_method())) + m_comp_methods.push_back(session.compression_method()); + + m_extensions.add(new Renegotiation_Extension(reneg_info)); + m_extensions.add(new SRP_Identifier(session.srp_identifier())); + m_extensions.add(new Server_Name_Indicator(session.server_info().hostname())); + m_extensions.add(new Session_Ticket(session.session_ticket())); + m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); + + if(policy.negotiate_heartbeat_support()) + m_extensions.add(new Heartbeat_Support_Indicator(true)); + + if(session.fragment_size() != 0) + m_extensions.add(new Maximum_Fragment_Length(session.fragment_size())); + + if(m_version.supports_negotiable_signature_algorithms()) + m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), + policy.allowed_signature_methods())); + + if(reneg_info.empty() && next_protocol) + m_extensions.add(new Next_Protocol_Notification()); + + hash.update(io.send(*this)); + } + +/* +* Read a counterparty client hello +*/ +Client_Hello::Client_Hello(const std::vector& buf, Handshake_Type type) + { + if(type == CLIENT_HELLO) + deserialize(buf); + else + deserialize_sslv2(buf); + } + +void Client_Hello::update_hello_cookie(const Hello_Verify_Request& hello_verify) + { + if(!m_version.is_datagram_protocol()) + throw std::runtime_error("Cannot use hello cookie with stream protocol"); + + m_hello_cookie = hello_verify.cookie(); + } + +/* +* Serialize a Client Hello message +*/ +std::vector Client_Hello::serialize() const + { + std::vector buf; + + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; + + append_tls_length_value(buf, m_session_id, 1); + + if(m_version.is_datagram_protocol()) + append_tls_length_value(buf, m_hello_cookie, 1); + + append_tls_length_value(buf, m_suites, 2); + append_tls_length_value(buf, m_comp_methods, 1); + + /* + * May not want to send extensions at all in some cases. If so, + * should include SCSV value (if reneg info is empty, if not we are + * renegotiating with a modern server) + */ + + buf += m_extensions.serialize(); + + return buf; + } + +void Client_Hello::deserialize_sslv2(const std::vector& buf) + { + if(buf.size() < 12 || buf[0] != 1) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + const size_t cipher_spec_len = make_u16bit(buf[3], buf[4]); + const size_t m_session_id_len = make_u16bit(buf[5], buf[6]); + const size_t challenge_len = make_u16bit(buf[7], buf[8]); + + const size_t expected_size = + (9 + m_session_id_len + cipher_spec_len + challenge_len); + + if(buf.size() != expected_size) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + if(m_session_id_len != 0 || cipher_spec_len % 3 != 0 || + (challenge_len < 16 || challenge_len > 32)) + { + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + } + + m_version = Protocol_Version(buf[1], buf[2]); + + for(size_t i = 9; i != 9 + cipher_spec_len; i += 3) + { + if(buf[i] != 0) // a SSLv2 cipherspec; ignore it + continue; + + m_suites.push_back(make_u16bit(buf[i+1], buf[i+2])); + } + + m_random.resize(challenge_len); + copy_mem(&m_random[0], &buf[9+cipher_spec_len+m_session_id_len], challenge_len); + + if(offered_suite(static_cast(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) + m_extensions.add(new Renegotiation_Extension()); + } + +/* +* Deserialize a Client Hello message +*/ +void Client_Hello::deserialize(const std::vector& buf) + { + if(buf.size() == 0) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + if(buf.size() < 41) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + TLS_Data_Reader reader(buf); + + const byte major_version = reader.get_byte(); + const byte minor_version = reader.get_byte(); + + m_version = Protocol_Version(major_version, minor_version); + + m_random = reader.get_fixed(32); + + if(m_version.is_datagram_protocol()) + m_hello_cookie = reader.get_range(1, 0, 255); + + m_session_id = reader.get_range(1, 0, 32); + + m_suites = reader.get_range_vector(2, 1, 32767); + + m_comp_methods = reader.get_range_vector(1, 1, 255); + + m_extensions.deserialize(reader); + + if(offered_suite(static_cast(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) + { + if(Renegotiation_Extension* reneg = m_extensions.get()) + { + if(!reneg->renegotiation_info().empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client send renegotiation SCSV and non-empty extension"); + } + else + { + // add fake extension + m_extensions.add(new Renegotiation_Extension()); + } + } + } + +/* +* Check if we offered this ciphersuite +*/ +bool Client_Hello::offered_suite(u16bit ciphersuite) const + { + for(size_t i = 0; i != m_suites.size(); ++i) + if(m_suites[i] == ciphersuite) + return true; + return false; + } + +} + +} diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp new file mode 100644 index 000000000..ae8b82fd4 --- /dev/null +++ b/src/lib/tls/msg_client_kex.cpp @@ -0,0 +1,419 @@ +/* +* Client Key Exchange Message +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +secure_vector strip_leading_zeros(const secure_vector& input) + { + size_t leading_zeros = 0; + + for(size_t i = 0; i != input.size(); ++i) + { + if(input[i] != 0) + break; + ++leading_zeros; + } + + secure_vector output(&input[leading_zeros], + &input[input.size()]); + return output; + } + +} + +/* +* Create a new Client Key Exchange message +*/ +Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + const Public_Key* server_public_key, + const std::string& hostname, + RandomNumberGenerator& rng) + { + const std::string kex_algo = state.ciphersuite().kex_algo(); + + if(kex_algo == "PSK") + { + std::string identity_hint = ""; + + if(state.server_kex()) + { + TLS_Data_Reader reader(state.server_kex()->params()); + identity_hint = reader.get_string(2, 0, 65535); + } + + const std::string hostname = state.client_hello()->sni_hostname(); + + const std::string psk_identity = creds.psk_identity("tls-client", + hostname, + identity_hint); + + append_tls_length_value(m_key_material, psk_identity, 2); + + SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity); + + std::vector zeros(psk.length()); + + append_tls_length_value(m_pre_master, zeros, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + else if(state.server_kex()) + { + TLS_Data_Reader reader(state.server_kex()->params()); + + SymmetricKey psk; + + if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") + { + std::string identity_hint = reader.get_string(2, 0, 65535); + + const std::string hostname = state.client_hello()->sni_hostname(); + + const std::string psk_identity = creds.psk_identity("tls-client", + hostname, + identity_hint); + + append_tls_length_value(m_key_material, psk_identity, 2); + + psk = creds.psk("tls-client", hostname, psk_identity); + } + + if(kex_algo == "DH" || kex_algo == "DHE_PSK") + { + BigInt p = BigInt::decode(reader.get_range(2, 1, 65535)); + BigInt g = BigInt::decode(reader.get_range(2, 1, 65535)); + BigInt Y = BigInt::decode(reader.get_range(2, 1, 65535)); + + if(reader.remaining_bytes()) + throw Decoding_Error("Bad params size for DH key exchange"); + + if(p.bits() < policy.minimum_dh_group_size()) + throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, + "Server sent DH group of " + + std::to_string(p.bits()) + + " bits, policy requires at least " + + std::to_string(policy.minimum_dh_group_size())); + + /* + * A basic check for key validity. As we do not know q here we + * cannot check that Y is in the right subgroup. However since + * our key is ephemeral there does not seem to be any + * advantage to bogus keys anyway. + */ + if(Y <= 1 || Y >= p - 1) + throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, + "Server sent bad DH key for DHE exchange"); + + DL_Group group(p, g); + + if(!group.verify_group(rng, true)) + throw Internal_Error("DH group failed validation, possible attack"); + + DH_PublicKey counterparty_key(group, Y); + + DH_PrivateKey priv_key(rng, group); + + PK_Key_Agreement ka(priv_key, "Raw"); + + secure_vector dh_secret = strip_leading_zeros( + ka.derive_key(0, counterparty_key.public_value()).bits_of()); + + if(kex_algo == "DH") + m_pre_master = dh_secret; + else + { + append_tls_length_value(m_pre_master, dh_secret, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + + append_tls_length_value(m_key_material, priv_key.public_value(), 2); + } + else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") + { + const byte curve_type = reader.get_byte(); + + if(curve_type != 3) + throw Decoding_Error("Server sent non-named ECC curve"); + + const u16bit curve_id = reader.get_u16bit(); + + const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); + + if(name == "") + throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id)); + + EC_Group group(name); + + std::vector ecdh_key = reader.get_range(1, 1, 255); + + ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve())); + + ECDH_PrivateKey priv_key(rng, group); + + PK_Key_Agreement ka(priv_key, "Raw"); + + secure_vector ecdh_secret = + ka.derive_key(0, counterparty_key.public_value()).bits_of(); + + if(kex_algo == "ECDH") + m_pre_master = ecdh_secret; + else + { + append_tls_length_value(m_pre_master, ecdh_secret, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + + append_tls_length_value(m_key_material, priv_key.public_value(), 1); + } + else if(kex_algo == "SRP_SHA") + { + const BigInt N = BigInt::decode(reader.get_range(2, 1, 65535)); + const BigInt g = BigInt::decode(reader.get_range(2, 1, 65535)); + std::vector salt = reader.get_range(1, 1, 255); + const BigInt B = BigInt::decode(reader.get_range(2, 1, 65535)); + + const std::string srp_group = srp6_group_identifier(N, g); + + const std::string srp_identifier = + creds.srp_identifier("tls-client", hostname); + + const std::string srp_password = + creds.srp_password("tls-client", hostname, srp_identifier); + + std::pair srp_vals = + srp6_client_agree(srp_identifier, + srp_password, + srp_group, + "SHA-1", + salt, + B, + rng); + + append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2); + m_pre_master = srp_vals.second.bits_of(); + } + else + { + throw Internal_Error("Client_Key_Exchange: Unknown kex " + + kex_algo); + } + + reader.assert_done(); + } + else + { + // No server key exchange msg better mean RSA kex + RSA key in cert + + if(kex_algo != "RSA") + throw Unexpected_Message("No server kex but negotiated kex " + kex_algo); + + if(!server_public_key) + throw Internal_Error("No server public key for RSA exchange"); + + if(auto rsa_pub = dynamic_cast(server_public_key)) + { + const Protocol_Version offered_version = state.client_hello()->version(); + + m_pre_master = rng.random_vec(48); + m_pre_master[0] = offered_version.major_version(); + m_pre_master[1] = offered_version.minor_version(); + + PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); + + std::vector encrypted_key = encryptor.encrypt(m_pre_master, rng); + + if(state.version() == Protocol_Version::SSL_V3) + m_key_material = encrypted_key; // no length field + else + append_tls_length_value(m_key_material, encrypted_key, 2); + } + else + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Expected a RSA key in server cert but got " + + server_public_key->algo_name()); + } + + state.hash().update(io.send(*this)); + } + +/* +* Read a Client Key Exchange message +*/ +Client_Key_Exchange::Client_Key_Exchange(const std::vector& contents, + const Handshake_State& state, + const Private_Key* server_rsa_kex_key, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng) + { + const std::string kex_algo = state.ciphersuite().kex_algo(); + + if(kex_algo == "RSA") + { + BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(), + "RSA key exchange negotiated so server sent a certificate"); + + if(!server_rsa_kex_key) + throw Internal_Error("Expected RSA kex but no server kex key set"); + + if(!dynamic_cast(server_rsa_kex_key)) + throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name()); + + PK_Decryptor_EME decryptor(*server_rsa_kex_key, "PKCS1v15"); + + Protocol_Version client_version = state.client_hello()->version(); + + /* + * This is used as the pre-master if RSA decryption fails. + * Otherwise we can be used as an oracle. See Bleichenbacher + * "Chosen Ciphertext Attacks against Protocols Based on RSA + * Encryption Standard PKCS #1", Crypto 98 + * + * Create it here instead if in the catch clause as otherwise we + * expose a timing channel WRT the generation of the fake value. + * Some timing channel likely remains due to exception handling + * and the like. + */ + secure_vector fake_pre_master = rng.random_vec(48); + fake_pre_master[0] = client_version.major_version(); + fake_pre_master[1] = client_version.minor_version(); + + try + { + if(state.version() == Protocol_Version::SSL_V3) + { + m_pre_master = decryptor.decrypt(contents); + } + else + { + TLS_Data_Reader reader(contents); + m_pre_master = decryptor.decrypt(reader.get_range(2, 0, 65535)); + } + + if(m_pre_master.size() != 48 || + client_version.major_version() != m_pre_master[0] || + client_version.minor_version() != m_pre_master[1]) + { + throw Decoding_Error("Client_Key_Exchange: Secret corrupted"); + } + } + catch(...) + { + m_pre_master = fake_pre_master; + } + } + else + { + TLS_Data_Reader reader(contents); + + SymmetricKey psk; + + if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") + { + const std::string psk_identity = reader.get_string(2, 0, 65535); + + psk = creds.psk("tls-server", + state.client_hello()->sni_hostname(), + psk_identity); + + if(psk.length() == 0) + { + if(policy.hide_unknown_users()) + psk = SymmetricKey(rng, 16); + else + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "No PSK for identifier " + psk_identity); + } + } + + if(kex_algo == "PSK") + { + std::vector zeros(psk.length()); + append_tls_length_value(m_pre_master, zeros, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + else if(kex_algo == "SRP_SHA") + { + SRP6_Server_Session& srp = state.server_kex()->server_srp_params(); + + m_pre_master = srp.step2(BigInt::decode(reader.get_range(2, 0, 65535))).bits_of(); + } + else if(kex_algo == "DH" || kex_algo == "DHE_PSK" || + kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") + { + const Private_Key& private_key = state.server_kex()->server_kex_key(); + + const PK_Key_Agreement_Key* ka_key = + dynamic_cast(&private_key); + + if(!ka_key) + throw Internal_Error("Expected key agreement key type but got " + + private_key.algo_name()); + + try + { + PK_Key_Agreement ka(*ka_key, "Raw"); + + std::vector client_pubkey; + + if(ka_key->algo_name() == "DH") + client_pubkey = reader.get_range(2, 0, 65535); + else + client_pubkey = reader.get_range(1, 0, 255); + + secure_vector shared_secret = ka.derive_key(0, client_pubkey).bits_of(); + + if(ka_key->algo_name() == "DH") + shared_secret = strip_leading_zeros(shared_secret); + + if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") + { + append_tls_length_value(m_pre_master, shared_secret, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + else + m_pre_master = shared_secret; + } + catch(std::exception &e) + { + /* + * Something failed in the DH computation. To avoid possible + * timing attacks, randomize the pre-master output and carry + * on, allowing the protocol to fail later in the finished + * checks. + */ + m_pre_master = rng.random_vec(ka_key->public_value().size()); + } + } + else + throw Internal_Error("Client_Key_Exchange: Unknown kex type " + kex_algo); + } + } + +} + +} diff --git a/src/lib/tls/msg_finished.cpp b/src/lib/tls/msg_finished.cpp new file mode 100644 index 000000000..c018497c8 --- /dev/null +++ b/src/lib/tls/msg_finished.cpp @@ -0,0 +1,104 @@ +/* +* Finished Message +* (C) 2004-2006,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +/* +* Compute the verify_data +*/ +std::vector finished_compute_verify(const Handshake_State& state, + Connection_Side side) + { + if(state.version() == Protocol_Version::SSL_V3) + { + const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 }; + const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 }; + + Handshake_Hash hash = state.hash(); // don't modify state + + std::vector ssl3_finished; + + if(side == CLIENT) + hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL)); + else + hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL)); + + return unlock(hash.final_ssl3(state.session_keys().master_secret())); + } + else + { + const byte TLS_CLIENT_LABEL[] = { + 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64 }; + + const byte TLS_SERVER_LABEL[] = { + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64 }; + + std::unique_ptr prf(state.protocol_specific_prf()); + + std::vector input; + if(side == CLIENT) + input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL)); + else + input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL)); + + input += state.hash().final(state.version(), state.ciphersuite().prf_algo()); + + return unlock(prf->derive_key(12, state.session_keys().master_secret(), input)); + } + } + +} + +/* +* Create a new Finished message +*/ +Finished::Finished(Handshake_IO& io, + Handshake_State& state, + Connection_Side side) + { + m_verification_data = finished_compute_verify(state, side); + state.hash().update(io.send(*this)); + } + +/* +* Serialize a Finished message +*/ +std::vector Finished::serialize() const + { + return m_verification_data; + } + +/* +* Deserialize a Finished message +*/ +Finished::Finished(const std::vector& buf) + { + m_verification_data = buf; + } + +/* +* Verify a Finished message +*/ +bool Finished::verify(const Handshake_State& state, + Connection_Side side) const + { + return (m_verification_data == finished_compute_verify(state, side)); + } + +} + +} diff --git a/src/lib/tls/msg_hello_verify.cpp b/src/lib/tls/msg_hello_verify.cpp new file mode 100644 index 000000000..f8a117c03 --- /dev/null +++ b/src/lib/tls/msg_hello_verify.cpp @@ -0,0 +1,69 @@ +/* +* DTLS Hello Verify Request +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Hello_Verify_Request::Hello_Verify_Request(const std::vector& buf) + { + if(buf.size() < 3) + throw Decoding_Error("Hello verify request too small"); + + Protocol_Version version(buf[0], buf[1]); + + if(version != Protocol_Version::DTLS_V10 && + version != Protocol_Version::DTLS_V12) + { + throw Decoding_Error("Unknown version from server in hello verify request"); + } + + if(static_cast(buf[2]) + 3 != buf.size()) + throw Decoding_Error("Bad length in hello verify request"); + + m_cookie.assign(&buf[3], &buf[buf.size()]); + } + +Hello_Verify_Request::Hello_Verify_Request(const std::vector& client_hello_bits, + const std::string& client_identity, + const SymmetricKey& secret_key) + { + std::unique_ptr hmac(get_mac("HMAC(SHA-256)")); + hmac->set_key(secret_key); + + hmac->update_be(client_hello_bits.size()); + hmac->update(client_hello_bits); + hmac->update_be(client_identity.size()); + hmac->update(client_identity); + + m_cookie = unlock(hmac->final()); + } + +std::vector Hello_Verify_Request::serialize() const + { + /* DTLS 1.2 server implementations SHOULD use DTLS version 1.0 + regardless of the version of TLS that is expected to be + negotiated (RFC 6347, section 4.2.1) + */ + + Protocol_Version format_version(Protocol_Version::DTLS_V10); + + std::vector bits; + bits.push_back(format_version.major_version()); + bits.push_back(format_version.minor_version()); + bits.push_back(static_cast(m_cookie.size())); + bits += m_cookie; + return bits; + } + +} + +} diff --git a/src/lib/tls/msg_next_protocol.cpp b/src/lib/tls/msg_next_protocol.cpp new file mode 100644 index 000000000..a09fd02d1 --- /dev/null +++ b/src/lib/tls/msg_next_protocol.cpp @@ -0,0 +1,55 @@ +/* +* Next Protocol Negotiation +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Next_Protocol::Next_Protocol(Handshake_IO& io, + Handshake_Hash& hash, + const std::string& protocol) : + m_protocol(protocol) + { + hash.update(io.send(*this)); + } + +Next_Protocol::Next_Protocol(const std::vector& buf) + { + TLS_Data_Reader reader(buf); + + m_protocol = reader.get_string(1, 0, 255); + + reader.get_range_vector(1, 0, 255); // padding, ignored + } + +std::vector Next_Protocol::serialize() const + { + std::vector buf; + + append_tls_length_value(buf, + reinterpret_cast(m_protocol.data()), + m_protocol.size(), + 1); + + const byte padding_len = 32 - ((m_protocol.size() + 2) % 32); + + buf.push_back(padding_len); + + for(size_t i = 0; i != padding_len; ++i) + buf.push_back(0); + + return buf; + } + +} + +} diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp new file mode 100644 index 000000000..a775e0b4b --- /dev/null +++ b/src/lib/tls/msg_server_hello.cpp @@ -0,0 +1,142 @@ +;/* +* TLS Server Hello and Server Hello Done +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/* +* Create a new Server Hello message +*/ +Server_Hello::Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + const std::vector& session_id, + Protocol_Version ver, + u16bit ciphersuite, + byte compression, + size_t max_fragment_size, + bool client_has_secure_renegotiation, + const std::vector& reneg_info, + bool offer_session_ticket, + bool client_has_npn, + const std::vector& next_protocols, + bool client_has_heartbeat, + RandomNumberGenerator& rng) : + m_version(ver), + m_session_id(session_id), + m_random(make_hello_random(rng)), + m_ciphersuite(ciphersuite), + m_comp_method(compression) + { + if(client_has_heartbeat && policy.negotiate_heartbeat_support()) + m_extensions.add(new Heartbeat_Support_Indicator(true)); + + /* + * Even a client that offered SSLv3 and sent the SCSV will get an + * extension back. This is probably the right thing to do. + */ + if(client_has_secure_renegotiation) + m_extensions.add(new Renegotiation_Extension(reneg_info)); + + if(max_fragment_size) + m_extensions.add(new Maximum_Fragment_Length(max_fragment_size)); + + if(client_has_npn) + m_extensions.add(new Next_Protocol_Notification(next_protocols)); + + if(offer_session_ticket) + m_extensions.add(new Session_Ticket()); + + hash.update(io.send(*this)); + } + +/* +* Deserialize a Server Hello message +*/ +Server_Hello::Server_Hello(const std::vector& buf) + { + if(buf.size() < 38) + throw Decoding_Error("Server_Hello: Packet corrupted"); + + TLS_Data_Reader reader(buf); + + const byte major_version = reader.get_byte(); + const byte minor_version = reader.get_byte(); + + m_version = Protocol_Version(major_version, minor_version); + + m_random = reader.get_fixed(32); + + m_session_id = reader.get_range(1, 0, 32); + + m_ciphersuite = reader.get_u16bit(); + + m_comp_method = reader.get_byte(); + + m_extensions.deserialize(reader); + } + +/* +* Serialize a Server Hello message +*/ +std::vector Server_Hello::serialize() const + { + std::vector buf; + + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; + + append_tls_length_value(buf, m_session_id, 1); + + buf.push_back(get_byte(0, m_ciphersuite)); + buf.push_back(get_byte(1, m_ciphersuite)); + + buf.push_back(m_comp_method); + + buf += m_extensions.serialize(); + + return buf; + } + +/* +* Create a new Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(Handshake_IO& io, + Handshake_Hash& hash) + { + hash.update(io.send(*this)); + } + +/* +* Deserialize a Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(const std::vector& buf) + { + if(buf.size()) + throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); + } + +/* +* Serialize a Server Hello Done message +*/ +std::vector Server_Hello_Done::serialize() const + { + return std::vector(); + } + +} + +} diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp new file mode 100644 index 000000000..b8293d3e8 --- /dev/null +++ b/src/lib/tls/msg_server_kex.cpp @@ -0,0 +1,285 @@ +/* +* Server Key Exchange Message +* (C) 2004-2010,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Create a new Server Key Exchange message +*/ +Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + RandomNumberGenerator& rng, + const Private_Key* signing_key) + { + const std::string hostname = state.client_hello()->sni_hostname(); + const std::string kex_algo = state.ciphersuite().kex_algo(); + + if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") + { + std::string identity_hint = + creds.psk_identity_hint("tls-server", hostname); + + append_tls_length_value(m_params, identity_hint, 2); + } + + if(kex_algo == "DH" || kex_algo == "DHE_PSK") + { + std::unique_ptr dh(new DH_PrivateKey(rng, policy.dh_group())); + + append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); + append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); + append_tls_length_value(m_params, dh->public_value(), 2); + m_kex_key.reset(dh.release()); + } + else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") + { + const std::vector& curves = + state.client_hello()->supported_ecc_curves(); + + if(curves.empty()) + throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); + + const std::string curve_name = policy.choose_curve(curves); + + if(curve_name == "") + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Could not agree on an ECC curve with the client"); + + EC_Group ec_group(curve_name); + + std::unique_ptr ecdh(new ECDH_PrivateKey(rng, ec_group)); + + const std::string ecdh_domain_oid = ecdh->domain().get_oid(); + const std::string domain = OIDS::lookup(OID(ecdh_domain_oid)); + + if(domain == "") + throw Internal_Error("Could not find name of ECDH domain " + ecdh_domain_oid); + + const u16bit named_curve_id = Supported_Elliptic_Curves::name_to_curve_id(domain); + + m_params.push_back(3); // named curve + m_params.push_back(get_byte(0, named_curve_id)); + m_params.push_back(get_byte(1, named_curve_id)); + + append_tls_length_value(m_params, ecdh->public_value(), 1); + + m_kex_key.reset(ecdh.release()); + } + else if(kex_algo == "SRP_SHA") + { + const std::string srp_identifier = state.client_hello()->srp_identifier(); + + std::string group_id; + BigInt v; + std::vector salt; + + const bool found = creds.srp_verifier("tls-server", hostname, + srp_identifier, + group_id, v, salt, + policy.hide_unknown_users()); + + if(!found) + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "Unknown SRP user " + srp_identifier); + + m_srp_params.reset(new SRP6_Server_Session); + + BigInt B = m_srp_params->step1(v, group_id, + "SHA-1", rng); + + DL_Group group(group_id); + + append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2); + append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2); + append_tls_length_value(m_params, salt, 1); + append_tls_length_value(m_params, BigInt::encode(B), 2); + } + else if(kex_algo != "PSK") + throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_algo); + + if(state.ciphersuite().sig_algo() != "") + { + BOTAN_ASSERT(signing_key, "Signing key was set"); + + std::pair format = + state.choose_sig_format(*signing_key, m_hash_algo, m_sig_algo, false, policy); + + PK_Signer signer(*signing_key, format.first, format.second); + + signer.update(state.client_hello()->random()); + signer.update(state.server_hello()->random()); + signer.update(params()); + m_signature = signer.signature(rng); + } + + state.hash().update(io.send(*this)); + } + +/** +* Deserialize a Server Key Exchange message +*/ +Server_Key_Exchange::Server_Key_Exchange(const std::vector& buf, + const std::string& kex_algo, + const std::string& sig_algo, + Protocol_Version version) : + m_kex_key(nullptr), m_srp_params(nullptr) + { + if(buf.size() < 6) + throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); + + TLS_Data_Reader reader(buf); + + /* + * We really are just serializing things back to what they were + * before, but unfortunately to know where the signature is we need + * to be able to parse the whole thing anyway. + */ + + if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") + { + const std::string identity_hint = reader.get_string(2, 0, 65535); + append_tls_length_value(m_params, identity_hint, 2); + } + + if(kex_algo == "DH" || kex_algo == "DHE_PSK") + { + // 3 bigints, DH p, g, Y + + for(size_t i = 0; i != 3; ++i) + { + BigInt v = BigInt::decode(reader.get_range(2, 1, 65535)); + append_tls_length_value(m_params, BigInt::encode(v), 2); + } + } + else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") + { + const byte curve_type = reader.get_byte(); + + if(curve_type != 3) + throw Decoding_Error("Server_Key_Exchange: Server sent non-named ECC curve"); + + const u16bit curve_id = reader.get_u16bit(); + + const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); + + std::vector ecdh_key = reader.get_range(1, 1, 255); + + if(name == "") + throw Decoding_Error("Server_Key_Exchange: Server sent unknown named curve " + + std::to_string(curve_id)); + + m_params.push_back(curve_type); + m_params.push_back(get_byte(0, curve_id)); + m_params.push_back(get_byte(1, curve_id)); + append_tls_length_value(m_params, ecdh_key, 1); + } + else if(kex_algo == "SRP_SHA") + { + // 2 bigints (N,g) then salt, then server B + + const BigInt N = BigInt::decode(reader.get_range(2, 1, 65535)); + const BigInt g = BigInt::decode(reader.get_range(2, 1, 65535)); + std::vector salt = reader.get_range(1, 1, 255); + const BigInt B = BigInt::decode(reader.get_range(2, 1, 65535)); + + append_tls_length_value(m_params, BigInt::encode(N), 2); + append_tls_length_value(m_params, BigInt::encode(g), 2); + append_tls_length_value(m_params, salt, 1); + append_tls_length_value(m_params, BigInt::encode(B), 2); + } + else if(kex_algo != "PSK") + throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_algo); + + if(sig_algo != "") + { + if(version.supports_negotiable_signature_algorithms()) + { + m_hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte()); + m_sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte()); + } + + m_signature = reader.get_range(2, 0, 65535); + } + + reader.assert_done(); + } + +Server_Key_Exchange::~Server_Key_Exchange() {} + +/** +* Serialize a Server Key Exchange message +*/ +std::vector Server_Key_Exchange::serialize() const + { + std::vector buf = params(); + + if(m_signature.size()) + { + // This should be an explicit version check + if(m_hash_algo != "" && m_sig_algo != "") + { + buf.push_back(Signature_Algorithms::hash_algo_code(m_hash_algo)); + buf.push_back(Signature_Algorithms::sig_algo_code(m_sig_algo)); + } + + append_tls_length_value(buf, m_signature, 2); + } + + return buf; + } + +/** +* Verify a Server Key Exchange message +*/ +bool Server_Key_Exchange::verify(const Public_Key& server_key, + const Handshake_State& state) const + { + std::pair format = + state.understand_sig_format(server_key, m_hash_algo, m_sig_algo, false); + + PK_Verifier verifier(server_key, format.first, format.second); + + verifier.update(state.client_hello()->random()); + verifier.update(state.server_hello()->random()); + verifier.update(params()); + + return verifier.check_signature(m_signature); + } + +const Private_Key& Server_Key_Exchange::server_kex_key() const + { + BOTAN_ASSERT_NONNULL(m_kex_key); + return *m_kex_key; + } + +// Only valid for SRP negotiation +SRP6_Server_Session& Server_Key_Exchange::server_srp_params() const + { + BOTAN_ASSERT_NONNULL(m_srp_params); + return *m_srp_params; + } +} + +} diff --git a/src/lib/tls/msg_session_ticket.cpp b/src/lib/tls/msg_session_ticket.cpp new file mode 100644 index 000000000..2bb9987a9 --- /dev/null +++ b/src/lib/tls/msg_session_ticket.cpp @@ -0,0 +1,57 @@ +/* +* Session Tickets +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& ticket, + u32bit lifetime) : + m_ticket_lifetime_hint(lifetime), + m_ticket(ticket) + { + hash.update(io.send(*this)); + } + +New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash) : + m_ticket_lifetime_hint(0) + { + hash.update(io.send(*this)); + } + +New_Session_Ticket::New_Session_Ticket(const std::vector& buf) : + m_ticket_lifetime_hint(0) + { + if(buf.size() < 6) + throw Decoding_Error("Session ticket message too short to be valid"); + + TLS_Data_Reader reader(buf); + + m_ticket_lifetime_hint = reader.get_u32bit(); + m_ticket = reader.get_range(2, 0, 65535); + } + +std::vector New_Session_Ticket::serialize() const + { + std::vector buf(4); + store_be(m_ticket_lifetime_hint, &buf[0]); + append_tls_length_value(buf, m_ticket, 2); + return buf; + } + +} + +} diff --git a/src/lib/tls/sessions_sqlite/info.txt b/src/lib/tls/sessions_sqlite/info.txt new file mode 100644 index 000000000..76d53f995 --- /dev/null +++ b/src/lib/tls/sessions_sqlite/info.txt @@ -0,0 +1,6 @@ +define TLS_SQLITE3_SESSION_MANAGER 20131128 + + +pbkdf2 +sqlite3 + diff --git a/src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.cpp b/src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.cpp new file mode 100644 index 000000000..d4f286a8d --- /dev/null +++ b/src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.cpp @@ -0,0 +1,223 @@ +/* +* SQLite TLS Session Manager +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +SymmetricKey derive_key(const std::string& passphrase, + const byte salt[], + size_t salt_len, + size_t iterations, + size_t& check_val) + { + std::unique_ptr pbkdf(get_pbkdf("PBKDF2(SHA-512)")); + + secure_vector x = pbkdf->derive_key(32 + 2, + passphrase, + salt, salt_len, + iterations).bits_of(); + + check_val = make_u16bit(x[0], x[1]); + return SymmetricKey(&x[2], x.size() - 2); + } + +} + +Session_Manager_SQLite::Session_Manager_SQLite(const std::string& passphrase, + RandomNumberGenerator& rng, + const std::string& db_filename, + size_t max_sessions, + std::chrono::seconds session_lifetime) : + m_rng(rng), + m_max_sessions(max_sessions), + m_session_lifetime(session_lifetime) + { + m_db = new sqlite3_database(db_filename); + + m_db->create_table( + "create table if not exists tls_sessions " + "(" + "session_id TEXT PRIMARY KEY, " + "session_start INTEGER, " + "hostname TEXT, " + "hostport INTEGER, " + "session BLOB" + ")"); + + m_db->create_table( + "create table if not exists tls_sessions_metadata " + "(" + "passphrase_salt BLOB, " + "passphrase_iterations INTEGER, " + "passphrase_check INTEGER " + ")"); + + const size_t salts = m_db->row_count("tls_sessions_metadata"); + + if(salts == 1) + { + // existing db + sqlite3_statement stmt(m_db, "select * from tls_sessions_metadata"); + + if(stmt.step()) + { + std::pair salt = stmt.get_blob(0); + const size_t iterations = stmt.get_size_t(1); + const size_t check_val_db = stmt.get_size_t(2); + + size_t check_val_created; + m_session_key = derive_key(passphrase, + salt.first, + salt.second, + iterations, + check_val_created); + + if(check_val_created != check_val_db) + throw std::runtime_error("Session database password not valid"); + } + } + else + { + // maybe just zap the salts + sessions tables in this case? + if(salts != 0) + throw std::runtime_error("Seemingly corrupted database, multiple salts found"); + + // new database case + + std::vector salt = unlock(rng.random_vec(16)); + const size_t iterations = 256 * 1024; + size_t check_val = 0; + + m_session_key = derive_key(passphrase, &salt[0], salt.size(), + iterations, check_val); + + sqlite3_statement stmt(m_db, "insert into tls_sessions_metadata" + " values(?1, ?2, ?3)"); + + stmt.bind(1, salt); + stmt.bind(2, iterations); + stmt.bind(3, check_val); + + stmt.spin(); + } + } + +Session_Manager_SQLite::~Session_Manager_SQLite() + { + delete m_db; + } + +bool Session_Manager_SQLite::load_from_session_id(const std::vector& session_id, + Session& session) + { + sqlite3_statement stmt(m_db, "select session from tls_sessions where session_id = ?1"); + + stmt.bind(1, hex_encode(session_id)); + + while(stmt.step()) + { + std::pair blob = stmt.get_blob(0); + + try + { + session = Session::decrypt(blob.first, blob.second, m_session_key); + return true; + } + catch(...) + { + } + } + + return false; + } + +bool Session_Manager_SQLite::load_from_server_info(const Server_Information& server, + Session& session) + { + sqlite3_statement stmt(m_db, "select session from tls_sessions" + " where hostname = ?1 and hostport = ?2" + " order by session_start desc"); + + stmt.bind(1, server.hostname()); + stmt.bind(2, server.port()); + + while(stmt.step()) + { + std::pair blob = stmt.get_blob(0); + + try + { + session = Session::decrypt(blob.first, blob.second, m_session_key); + return true; + } + catch(...) + { + } + } + + return false; + } + +void Session_Manager_SQLite::remove_entry(const std::vector& session_id) + { + sqlite3_statement stmt(m_db, "delete from tls_sessions where session_id = ?1"); + + stmt.bind(1, hex_encode(session_id)); + + stmt.spin(); + } + +void Session_Manager_SQLite::save(const Session& session) + { + sqlite3_statement stmt(m_db, "insert or replace into tls_sessions" + " values(?1, ?2, ?3, ?4, ?5)"); + + stmt.bind(1, hex_encode(session.session_id())); + stmt.bind(2, session.start_time()); + stmt.bind(3, session.server_info().hostname()); + stmt.bind(4, session.server_info().port()); + stmt.bind(5, session.encrypt(m_session_key, m_rng)); + + stmt.spin(); + + prune_session_cache(); + } + +void Session_Manager_SQLite::prune_session_cache() + { + sqlite3_statement remove_expired(m_db, "delete from tls_sessions where session_start <= ?1"); + + remove_expired.bind(1, std::chrono::system_clock::now() - m_session_lifetime); + + remove_expired.spin(); + + const size_t sessions = m_db->row_count("tls_sessions"); + + if(sessions > m_max_sessions) + { + sqlite3_statement remove_some(m_db, "delete from tls_sessions where session_id in " + "(select session_id from tls_sessions limit ?1)"); + + remove_some.bind(1, sessions - m_max_sessions); + remove_some.spin(); + } + } + +} + +} diff --git a/src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.h b/src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.h new file mode 100644 index 000000000..7892ccd6a --- /dev/null +++ b/src/lib/tls/sessions_sqlite/tls_session_manager_sqlite.h @@ -0,0 +1,80 @@ +/* +* SQLite3 TLS Session Manager +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SQLITE3_SESSION_MANAGER_H__ +#define BOTAN_TLS_SQLITE3_SESSION_MANAGER_H__ + +#include +#include + +namespace Botan { + +class sqlite3_database; + +namespace TLS { + +/** +* An implementation of Session_Manager that saves values in a SQLite3 +* database file, with the session data encrypted using a passphrase. +* +* @warning For clients, the hostnames associated with the saved +* sessions are stored in the database in plaintext. This may be a +* serious privacy risk in some situations. +*/ +class BOTAN_DLL Session_Manager_SQLite : public Session_Manager + { + public: + /** + * @param passphrase used to encrypt the session data + * @param rng a random number generator + * @param db_filename filename of the SQLite database file. + The table names tls_sessions and tls_sessions_metadata + will be used + * @param max_sessions a hint on the maximum number of sessions + * to keep in memory at any one time. (If zero, don't cap) + * @param session_lifetime sessions are expired after this many + * seconds have elapsed from initial handshake. + */ + Session_Manager_SQLite(const std::string& passphrase, + RandomNumberGenerator& rng, + const std::string& db_filename, + size_t max_sessions = 1000, + std::chrono::seconds session_lifetime = std::chrono::seconds(7200)); + + ~Session_Manager_SQLite(); + + bool load_from_session_id(const std::vector& session_id, + Session& session) override; + + bool load_from_server_info(const Server_Information& info, + Session& session) override; + + void remove_entry(const std::vector& session_id) override; + + void save(const Session& session_data) override; + + std::chrono::seconds session_lifetime() const override + { return m_session_lifetime; } + + private: + Session_Manager_SQLite(const Session_Manager_SQLite&); + Session_Manager_SQLite& operator=(const Session_Manager_SQLite&); + + void prune_session_cache(); + + SymmetricKey m_session_key; + RandomNumberGenerator& m_rng; + size_t m_max_sessions; + std::chrono::seconds m_session_lifetime; + sqlite3_database* m_db; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_alert.cpp b/src/lib/tls/tls_alert.cpp new file mode 100644 index 000000000..15bb2a2dc --- /dev/null +++ b/src/lib/tls/tls_alert.cpp @@ -0,0 +1,123 @@ +/* +* Alert Message +* (C) 2004-2006,2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +Alert::Alert(const secure_vector& buf) + { + if(buf.size() != 2) + throw Decoding_Error("Alert: Bad size " + std::to_string(buf.size()) + + " for alert message"); + + if(buf[0] == 1) m_fatal = false; + else if(buf[0] == 2) m_fatal = true; + else + throw Decoding_Error("Alert: Bad code for alert level"); + + const byte dc = buf[1]; + + m_type_code = static_cast(dc); + } + +std::vector Alert::serialize() const + { + return std::vector({ + static_cast(is_fatal() ? 2 : 1), + static_cast(type()) + }); + } + +std::string Alert::type_string() const + { + switch(type()) + { + case CLOSE_NOTIFY: + return "close_notify"; + case UNEXPECTED_MESSAGE: + return "unexpected_message"; + case BAD_RECORD_MAC: + return "bad_record_mac"; + case DECRYPTION_FAILED: + return "decryption_failed"; + case RECORD_OVERFLOW: + return "record_overflow"; + case DECOMPRESSION_FAILURE: + return "decompression_failure"; + case HANDSHAKE_FAILURE: + return "handshake_failure"; + case NO_CERTIFICATE: + return "no_certificate"; + case BAD_CERTIFICATE: + return "bad_certificate"; + case UNSUPPORTED_CERTIFICATE: + return "unsupported_certificate"; + case CERTIFICATE_REVOKED: + return "certificate_revoked"; + case CERTIFICATE_EXPIRED: + return "certificate_expired"; + case CERTIFICATE_UNKNOWN: + return "certificate_unknown"; + case ILLEGAL_PARAMETER: + return "illegal_parameter"; + case UNKNOWN_CA: + return "unknown_ca"; + case ACCESS_DENIED: + return "access_denied"; + case DECODE_ERROR: + return "decode_error"; + case DECRYPT_ERROR: + return "decrypt_error"; + case EXPORT_RESTRICTION: + return "export_restriction"; + case PROTOCOL_VERSION: + return "protocol_version"; + case INSUFFICIENT_SECURITY: + return "insufficient_security"; + case INTERNAL_ERROR: + return "internal_error"; + case USER_CANCELED: + return "user_canceled"; + case NO_RENEGOTIATION: + return "no_renegotiation"; + + case UNSUPPORTED_EXTENSION: + return "unsupported_extension"; + case CERTIFICATE_UNOBTAINABLE: + return "certificate_unobtainable"; + case UNRECOGNIZED_NAME: + return "unrecognized_name"; + case BAD_CERTIFICATE_STATUS_RESPONSE: + return "bad_certificate_status_response"; + case BAD_CERTIFICATE_HASH_VALUE: + return "bad_certificate_hash_value"; + case UNKNOWN_PSK_IDENTITY: + return "unknown_psk_identity"; + + case NULL_ALERT: + return "none"; + + case HEARTBEAT_PAYLOAD: + return "heartbeat_payload"; + } + + /* + * This is effectively the default case for the switch above, but we + * leave it out so that when an alert type is added to the enum the + * compiler can warn us that it is not included in the switch + * statement. + */ + return "unrecognized_alert_" + std::to_string(type()); + } + +} + +} diff --git a/src/lib/tls/tls_alert.h b/src/lib/tls/tls_alert.h new file mode 100644 index 000000000..bf32178ee --- /dev/null +++ b/src/lib/tls/tls_alert.h @@ -0,0 +1,113 @@ +/* +* Alert Message +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_ALERT_H__ +#define BOTAN_TLS_ALERT_H__ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* SSL/TLS Alert Message +*/ +class BOTAN_DLL Alert + { + public: + /** + * Type codes for TLS alerts + */ + enum Type { + CLOSE_NOTIFY = 0, + UNEXPECTED_MESSAGE = 10, + BAD_RECORD_MAC = 20, + DECRYPTION_FAILED = 21, + RECORD_OVERFLOW = 22, + DECOMPRESSION_FAILURE = 30, + HANDSHAKE_FAILURE = 40, + NO_CERTIFICATE = 41, // SSLv3 only + BAD_CERTIFICATE = 42, + UNSUPPORTED_CERTIFICATE = 43, + CERTIFICATE_REVOKED = 44, + CERTIFICATE_EXPIRED = 45, + CERTIFICATE_UNKNOWN = 46, + ILLEGAL_PARAMETER = 47, + UNKNOWN_CA = 48, + ACCESS_DENIED = 49, + DECODE_ERROR = 50, + DECRYPT_ERROR = 51, + EXPORT_RESTRICTION = 60, + PROTOCOL_VERSION = 70, + INSUFFICIENT_SECURITY = 71, + INTERNAL_ERROR = 80, + USER_CANCELED = 90, + NO_RENEGOTIATION = 100, + UNSUPPORTED_EXTENSION = 110, + CERTIFICATE_UNOBTAINABLE = 111, + UNRECOGNIZED_NAME = 112, + BAD_CERTIFICATE_STATUS_RESPONSE = 113, + BAD_CERTIFICATE_HASH_VALUE = 114, + UNKNOWN_PSK_IDENTITY = 115, + + // pseudo alert values + NULL_ALERT = 256, + HEARTBEAT_PAYLOAD = 257 + }; + + /** + * @return true iff this alert is non-empty + */ + bool is_valid() const { return (m_type_code != NULL_ALERT); } + + /** + * @return if this alert is a fatal one or not + */ + bool is_fatal() const { return m_fatal; } + + /** + * @return type of alert + */ + Type type() const { return m_type_code; } + + /** + * @return type of alert + */ + std::string type_string() const; + + /** + * Serialize an alert + */ + std::vector serialize() const; + + /** + * Deserialize an Alert message + * @param buf the serialized alert + */ + Alert(const secure_vector& buf); + + /** + * Create a new Alert + * @param type_code the type of alert + * @param fatal specifies if this is a fatal alert + */ + Alert(Type type_code, bool fatal = false) : + m_fatal(fatal), m_type_code(type_code) {} + + Alert() : m_fatal(false), m_type_code(NULL_ALERT) {} + private: + bool m_fatal; + Type m_type_code; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_blocking.cpp b/src/lib/tls/tls_blocking.cpp new file mode 100644 index 000000000..4b33ba926 --- /dev/null +++ b/src/lib/tls/tls_blocking.cpp @@ -0,0 +1,90 @@ +/* +* TLS Blocking API +* (C) 2013 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace TLS { + +using namespace std::placeholders; + +Blocking_Client::Blocking_Client(std::function read_fn, + std::function write_fn, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info, + const Protocol_Version offer_version, + std::function)> next_protocol) : + m_read_fn(read_fn), + m_channel(write_fn, + std::bind(&Blocking_Client::data_cb, this, _1, _2), + std::bind(&Blocking_Client::alert_cb, this, _1, _2, _3), + std::bind(&Blocking_Client::handshake_cb, this, _1), + session_manager, + creds, + policy, + rng, + server_info, + offer_version, + next_protocol) + { + } + +bool Blocking_Client::handshake_cb(const Session& session) + { + return this->handshake_complete(session); + } + +void Blocking_Client::alert_cb(const Alert alert, const byte[], size_t) + { + this->alert_notification(alert); + } + +void Blocking_Client::data_cb(const byte data[], size_t data_len) + { + m_plaintext.insert(m_plaintext.end(), data, data + data_len); + } + +void Blocking_Client::do_handshake() + { + std::vector readbuf(4096); + + while(!m_channel.is_closed() && !m_channel.is_active()) + { + const size_t from_socket = m_read_fn(&readbuf[0], readbuf.size()); + m_channel.received_data(&readbuf[0], from_socket); + } + } + +size_t Blocking_Client::read(byte buf[], size_t buf_len) + { + std::vector readbuf(4096); + + while(m_plaintext.empty() && !m_channel.is_closed()) + { + const size_t from_socket = m_read_fn(&readbuf[0], readbuf.size()); + m_channel.received_data(&readbuf[0], from_socket); + } + + const size_t returned = std::min(buf_len, m_plaintext.size()); + + for(size_t i = 0; i != returned; ++i) + buf[i] = m_plaintext[i]; + m_plaintext.erase(m_plaintext.begin(), m_plaintext.begin() + returned); + + BOTAN_ASSERT_IMPLICATION(returned == 0, m_channel.is_closed(), + "Only return zero if channel is closed"); + + return returned; + } + +} + +} diff --git a/src/lib/tls/tls_blocking.h b/src/lib/tls/tls_blocking.h new file mode 100644 index 000000000..cfa96ce8d --- /dev/null +++ b/src/lib/tls/tls_blocking.h @@ -0,0 +1,97 @@ +/* +* TLS Blocking API +* (C) 2013 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_BLOCKING_CHANNELS_H__ +#define BOTAN_TLS_BLOCKING_CHANNELS_H__ + +#include +#include +#include + +namespace Botan { + +template using secure_deque = std::vector>; + +namespace TLS { + +/** +* Blocking TLS Client +*/ +class BOTAN_DLL Blocking_Client + { + public: + + Blocking_Client(std::function read_fn, + std::function write_fn, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version offer_version = Protocol_Version::latest_tls_version(), + std::function)> next_protocol = + std::function)>()); + + /** + * Completes full handshake then returns + */ + void do_handshake(); + + /** + * Number of bytes pending read in the plaintext buffer (bytes + * readable without blocking) + */ + size_t pending() const { return m_plaintext.size(); } + + /** + * Blocking read, will return at least 1 byte or 0 on connection close + */ + size_t read(byte buf[], size_t buf_len); + + void write(const byte buf[], size_t buf_len) { m_channel.send(buf, buf_len); } + + const TLS::Channel& underlying_channel() const { return m_channel; } + TLS::Channel& underlying_channel() { return m_channel; } + + void close() { m_channel.close(); } + + bool is_closed() const { return m_channel.is_closed(); } + + std::vector peer_cert_chain() const + { return m_channel.peer_cert_chain(); } + + virtual ~Blocking_Client() {} + + protected: + /** + * Can override to get the handshake complete notification + */ + virtual bool handshake_complete(const Session&) { return true; } + + /** + * Can override to get notification of alerts + */ + virtual void alert_notification(const Alert&) {} + + private: + + bool handshake_cb(const Session&); + + void data_cb(const byte data[], size_t data_len); + + void alert_cb(const Alert alert, const byte data[], size_t data_len); + + std::function m_read_fn; + TLS::Client m_channel; + secure_deque m_plaintext; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp new file mode 100644 index 000000000..8ed876b3f --- /dev/null +++ b/src/lib/tls/tls_channel.cpp @@ -0,0 +1,668 @@ +/* +* TLS Channels +* (C) 2011-2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Channel::Channel(std::function output_fn, + std::function data_cb, + std::function alert_cb, + std::function handshake_cb, + Session_Manager& session_manager, + RandomNumberGenerator& rng, + size_t reserved_io_buffer_size) : + m_handshake_cb(handshake_cb), + m_data_cb(data_cb), + m_alert_cb(alert_cb), + m_output_fn(output_fn), + m_rng(rng), + m_session_manager(session_manager) + { + m_writebuf.reserve(reserved_io_buffer_size); + m_readbuf.reserve(reserved_io_buffer_size); + } + +void Channel::reset_state() + { + m_active_state.reset(); + m_pending_state.reset(); + m_readbuf.clear(); + m_write_cipher_states.clear(); + m_read_cipher_states.clear(); + } + +Channel::~Channel() + { + // So unique_ptr destructors run correctly + } + +Connection_Sequence_Numbers& Channel::sequence_numbers() const + { + BOTAN_ASSERT(m_sequence_numbers, "Have a sequence numbers object"); + return *m_sequence_numbers; + } + +std::shared_ptr Channel::read_cipher_state_epoch(u16bit epoch) const + { + auto i = m_read_cipher_states.find(epoch); + + BOTAN_ASSERT(i != m_read_cipher_states.end(), + "Have a cipher state for the specified epoch"); + + return i->second; + } + +std::shared_ptr Channel::write_cipher_state_epoch(u16bit epoch) const + { + auto i = m_write_cipher_states.find(epoch); + + BOTAN_ASSERT(i != m_write_cipher_states.end(), + "Have a cipher state for the specified epoch"); + + return i->second; + } + +std::vector Channel::peer_cert_chain() const + { + if(auto active = active_state()) + return get_peer_cert_chain(*active); + return std::vector(); + } + +Handshake_State& Channel::create_handshake_state(Protocol_Version version) + { + if(pending_state()) + throw Internal_Error("create_handshake_state called during handshake"); + + if(auto active = active_state()) + { + Protocol_Version active_version = active->version(); + + if(active_version.is_datagram_protocol() != version.is_datagram_protocol()) + throw std::runtime_error("Active state using version " + + active_version.to_string() + + " cannot change to " + + version.to_string() + + " in pending"); + } + + if(!m_sequence_numbers) + { + if(version.is_datagram_protocol()) + m_sequence_numbers.reset(new Datagram_Sequence_Numbers); + else + m_sequence_numbers.reset(new Stream_Sequence_Numbers); + } + + std::unique_ptr io; + if(version.is_datagram_protocol()) + io.reset(new Datagram_Handshake_IO( + sequence_numbers(), + std::bind(&Channel::send_record_under_epoch, this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3))); + else + io.reset(new Stream_Handshake_IO( + std::bind(&Channel::send_record, this, + std::placeholders::_1, + std::placeholders::_2))); + + m_pending_state.reset(new_handshake_state(io.release())); + + if(auto active = active_state()) + m_pending_state->set_version(active->version()); + + return *m_pending_state.get(); + } + +void Channel::renegotiate(bool force_full_renegotiation) + { + if(pending_state()) // currently in handshake? + return; + + if(auto active = active_state()) + initiate_handshake(create_handshake_state(active->version()), + force_full_renegotiation); + else + throw std::runtime_error("Cannot renegotiate on inactive connection"); + } + +size_t Channel::maximum_fragment_size() const + { + // should we be caching this value? + + if(auto pending = pending_state()) + if(auto server_hello = pending->server_hello()) + if(size_t frag = server_hello->fragment_size()) + return frag; + + if(auto active = active_state()) + if(size_t frag = active->server_hello()->fragment_size()) + return frag; + + return MAX_PLAINTEXT_SIZE; + } + +void Channel::change_cipher_spec_reader(Connection_Side side) + { + auto pending = pending_state(); + + BOTAN_ASSERT(pending && pending->server_hello(), + "Have received server hello"); + + if(pending->server_hello()->compression_method() != NO_COMPRESSION) + throw Internal_Error("Negotiated unknown compression algorithm"); + + sequence_numbers().new_read_cipher_state(); + + const u16bit epoch = sequence_numbers().current_read_epoch(); + + BOTAN_ASSERT(m_read_cipher_states.count(epoch) == 0, + "No read cipher state currently set for next epoch"); + + // flip side as we are reading + std::shared_ptr read_state( + new Connection_Cipher_State(pending->version(), + (side == CLIENT) ? SERVER : CLIENT, + false, + pending->ciphersuite(), + pending->session_keys())); + + m_read_cipher_states[epoch] = read_state; + } + +void Channel::change_cipher_spec_writer(Connection_Side side) + { + auto pending = pending_state(); + + BOTAN_ASSERT(pending && pending->server_hello(), + "Have received server hello"); + + if(pending->server_hello()->compression_method() != NO_COMPRESSION) + throw Internal_Error("Negotiated unknown compression algorithm"); + + sequence_numbers().new_write_cipher_state(); + + const u16bit epoch = sequence_numbers().current_write_epoch(); + + BOTAN_ASSERT(m_write_cipher_states.count(epoch) == 0, + "No write cipher state currently set for next epoch"); + + std::shared_ptr write_state( + new Connection_Cipher_State(pending->version(), + side, + true, + pending->ciphersuite(), + pending->session_keys())); + + m_write_cipher_states[epoch] = write_state; + } + +bool Channel::is_active() const + { + return (active_state() != nullptr); + } + +bool Channel::is_closed() const + { + if(active_state() || pending_state()) + return false; + + /* + * If no active or pending state, then either we had a connection + * and it has been closed, or we are a server which has never + * received a connection. This case is detectable by also lacking + * m_sequence_numbers + */ + return (m_sequence_numbers != nullptr); + } + +void Channel::activate_session() + { + std::swap(m_active_state, m_pending_state); + m_pending_state.reset(); + + if(m_active_state->version().is_datagram_protocol()) + { + // FIXME, remove old states when we are sure not needed anymore + } + else + { + // TLS is easy just remove all but the current state + auto current_epoch = sequence_numbers().current_write_epoch(); + + const auto not_current_epoch = + [current_epoch](u16bit epoch) { return (epoch != current_epoch); }; + + map_remove_if(not_current_epoch, m_write_cipher_states); + map_remove_if(not_current_epoch, m_read_cipher_states); + } + } + +bool Channel::peer_supports_heartbeats() const + { + if(auto active = active_state()) + return active->server_hello()->supports_heartbeats(); + return false; + } + +bool Channel::heartbeat_sending_allowed() const + { + if(auto active = active_state()) + return active->server_hello()->peer_can_send_heartbeats(); + return false; + } + +size_t Channel::received_data(const std::vector& buf) + { + return this->received_data(&buf[0], buf.size()); + } + +size_t Channel::received_data(const byte input[], size_t input_size) + { + const auto get_cipherstate = [this](u16bit epoch) + { return this->read_cipher_state_epoch(epoch).get(); }; + + const size_t max_fragment_size = maximum_fragment_size(); + + try + { + while(!is_closed() && input_size) + { + secure_vector record; + u64bit record_sequence = 0; + Record_Type record_type = NO_RECORD; + Protocol_Version record_version; + + size_t consumed = 0; + + const size_t needed = + read_record(m_readbuf, + input, + input_size, + consumed, + record, + &record_sequence, + &record_version, + &record_type, + m_sequence_numbers.get(), + get_cipherstate); + + BOTAN_ASSERT(consumed <= input_size, + "Record reader consumed sane amount"); + + input += consumed; + input_size -= consumed; + + BOTAN_ASSERT(input_size == 0 || needed == 0, + "Got a full record or consumed all input"); + + if(input_size == 0 && needed != 0) + return needed; // need more data to complete record + + if(record.size() > max_fragment_size) + throw TLS_Exception(Alert::RECORD_OVERFLOW, + "Plaintext record is too large"); + + if(record_type == HANDSHAKE || record_type == CHANGE_CIPHER_SPEC) + { + if(!m_pending_state) + { + create_handshake_state(record_version); + if(record_version.is_datagram_protocol()) + sequence_numbers().read_accept(record_sequence); + } + + m_pending_state->handshake_io().add_record(unlock(record), + record_type, + record_sequence); + + while(auto pending = m_pending_state.get()) + { + auto msg = pending->get_next_handshake_msg(); + + if(msg.first == HANDSHAKE_NONE) // no full handshake yet + break; + + process_handshake_msg(active_state(), *pending, + msg.first, msg.second); + } + } + else if(record_type == HEARTBEAT && peer_supports_heartbeats()) + { + if(!active_state()) + throw Unexpected_Message("Heartbeat sent before handshake done"); + + Heartbeat_Message heartbeat(unlock(record)); + + const std::vector& payload = heartbeat.payload(); + + if(heartbeat.is_request()) + { + if(!pending_state()) + { + Heartbeat_Message response(Heartbeat_Message::RESPONSE, + &payload[0], payload.size()); + + send_record(HEARTBEAT, response.contents()); + } + } + else + { + m_alert_cb(Alert(Alert::HEARTBEAT_PAYLOAD), &payload[0], payload.size()); + } + } + else if(record_type == APPLICATION_DATA) + { + if(!active_state()) + throw Unexpected_Message("Application data before handshake done"); + + /* + * OpenSSL among others sends empty records in versions + * before TLS v1.1 in order to randomize the IV of the + * following record. Avoid spurious callbacks. + */ + if(record.size() > 0) + m_data_cb(&record[0], record.size()); + } + else if(record_type == ALERT) + { + Alert alert_msg(record); + + if(alert_msg.type() == Alert::NO_RENEGOTIATION) + m_pending_state.reset(); + + m_alert_cb(alert_msg, nullptr, 0); + + if(alert_msg.is_fatal()) + { + if(auto active = active_state()) + m_session_manager.remove_entry(active->server_hello()->session_id()); + } + + if(alert_msg.type() == Alert::CLOSE_NOTIFY) + send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind + + if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal()) + { + reset_state(); + return 0; + } + } + else + throw Unexpected_Message("Unexpected record type " + + std::to_string(record_type) + + " from counterparty"); + } + + return 0; // on a record boundary + } + catch(TLS_Exception& e) + { + send_fatal_alert(e.type()); + throw; + } + catch(Integrity_Failure& e) + { + send_fatal_alert(Alert::BAD_RECORD_MAC); + throw; + } + catch(Decoding_Error& e) + { + send_fatal_alert(Alert::DECODE_ERROR); + throw; + } + catch(...) + { + send_fatal_alert(Alert::INTERNAL_ERROR); + throw; + } + } + +void Channel::heartbeat(const byte payload[], size_t payload_size) + { + if(heartbeat_sending_allowed()) + { + Heartbeat_Message heartbeat(Heartbeat_Message::REQUEST, + payload, payload_size); + + send_record(HEARTBEAT, heartbeat.contents()); + } + } + +void Channel::write_record(Connection_Cipher_State* cipher_state, + byte record_type, const byte input[], size_t length) + { + BOTAN_ASSERT(m_pending_state || m_active_state, + "Some connection state exists"); + + Protocol_Version record_version = + (m_pending_state) ? (m_pending_state->version()) : (m_active_state->version()); + + TLS::write_record(m_writebuf, + record_type, + input, + length, + record_version, + sequence_numbers().next_write_sequence(), + cipher_state, + m_rng); + + m_output_fn(&m_writebuf[0], m_writebuf.size()); + } + +void Channel::send_record_array(u16bit epoch, byte type, const byte input[], size_t length) + { + if(length == 0) + return; + + /* + * If using CBC mode without an explicit IV (SSL v3 or TLS v1.0), + * send a single byte of plaintext to randomize the (implicit) IV of + * the following main block. If using a stream cipher, or TLS v1.1 + * or higher, this isn't necessary. + * + * An empty record also works but apparently some implementations do + * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814) + * + * See http://www.openssl.org/~bodo/tls-cbc.txt for background. + */ + + auto cipher_state = write_cipher_state_epoch(epoch); + + if(type == APPLICATION_DATA && cipher_state->cbc_without_explicit_iv()) + { + write_record(cipher_state.get(), type, &input[0], 1); + input += 1; + length -= 1; + } + + const size_t max_fragment_size = maximum_fragment_size(); + + while(length) + { + const size_t sending = std::min(length, max_fragment_size); + write_record(cipher_state.get(), type, &input[0], sending); + + input += sending; + length -= sending; + } + } + +void Channel::send_record(byte record_type, const std::vector& record) + { + send_record_array(sequence_numbers().current_write_epoch(), + record_type, &record[0], record.size()); + } + +void Channel::send_record_under_epoch(u16bit epoch, byte record_type, + const std::vector& record) + { + send_record_array(epoch, record_type, &record[0], record.size()); + } + +void Channel::send(const byte buf[], size_t buf_size) + { + if(!is_active()) + throw std::runtime_error("Data cannot be sent on inactive TLS connection"); + + send_record_array(sequence_numbers().current_write_epoch(), + APPLICATION_DATA, buf, buf_size); + } + +void Channel::send(const std::string& string) + { + this->send(reinterpret_cast(string.c_str()), string.size()); + } + +void Channel::send_alert(const Alert& alert) + { + if(alert.is_valid() && !is_closed()) + { + try + { + send_record(ALERT, alert.serialize()); + } + catch(...) { /* swallow it */ } + } + + if(alert.type() == Alert::NO_RENEGOTIATION) + m_pending_state.reset(); + + if(alert.is_fatal()) + if(auto active = active_state()) + m_session_manager.remove_entry(active->server_hello()->session_id()); + + if(alert.type() == Alert::CLOSE_NOTIFY || alert.is_fatal()) + reset_state(); + } + +void Channel::secure_renegotiation_check(const Client_Hello* client_hello) + { + const bool secure_renegotiation = client_hello->secure_renegotiation(); + + if(auto active = active_state()) + { + const bool active_sr = active->client_hello()->secure_renegotiation(); + + if(active_sr != secure_renegotiation) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client changed its mind about secure renegotiation"); + } + + if(secure_renegotiation) + { + const std::vector& data = client_hello->renegotiation_info(); + + if(data != secure_renegotiation_data_for_client_hello()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client sent bad values for secure renegotiation"); + } + } + +void Channel::secure_renegotiation_check(const Server_Hello* server_hello) + { + const bool secure_renegotiation = server_hello->secure_renegotiation(); + + if(auto active = active_state()) + { + const bool active_sr = active->client_hello()->secure_renegotiation(); + + if(active_sr != secure_renegotiation) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server changed its mind about secure renegotiation"); + } + + if(secure_renegotiation) + { + const std::vector& data = server_hello->renegotiation_info(); + + if(data != secure_renegotiation_data_for_server_hello()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent bad values for secure renegotiation"); + } + } + +std::vector Channel::secure_renegotiation_data_for_client_hello() const + { + if(auto active = active_state()) + return active->client_finished()->verify_data(); + return std::vector(); + } + +std::vector Channel::secure_renegotiation_data_for_server_hello() const + { + if(auto active = active_state()) + { + std::vector buf = active->client_finished()->verify_data(); + buf += active->server_finished()->verify_data(); + return buf; + } + + return std::vector(); + } + +bool Channel::secure_renegotiation_supported() const + { + if(auto active = active_state()) + return active->server_hello()->secure_renegotiation(); + + if(auto pending = pending_state()) + if(auto hello = pending->server_hello()) + return hello->secure_renegotiation(); + + return false; + } + +SymmetricKey Channel::key_material_export(const std::string& label, + const std::string& context, + size_t length) const + { + if(auto active = active_state()) + { + std::unique_ptr prf(active->protocol_specific_prf()); + + const secure_vector& master_secret = + active->session_keys().master_secret(); + + std::vector salt; + salt += to_byte_vector(label); + salt += active->client_hello()->random(); + salt += active->server_hello()->random(); + + if(context != "") + { + size_t context_size = context.length(); + if(context_size > 0xFFFF) + throw std::runtime_error("key_material_export context is too long"); + salt.push_back(get_byte(0, context_size)); + salt.push_back(get_byte(1, context_size)); + salt += to_byte_vector(context); + } + + return prf->derive_key(length, master_secret, salt); + } + else + throw std::runtime_error("Channel::key_material_export connection not active"); + } + +} + +} + diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h new file mode 100644 index 000000000..e7b53f563 --- /dev/null +++ b/src/lib/tls/tls_channel.h @@ -0,0 +1,259 @@ +/* +* TLS Channel +* (C) 2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_CHANNEL_H__ +#define BOTAN_TLS_CHANNEL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Connection_Cipher_State; +class Connection_Sequence_Numbers; +class Handshake_State; + +/** +* Generic interface for TLS endpoint +*/ +class BOTAN_DLL Channel + { + public: + /** + * Inject TLS traffic received from counterparty + * @return a hint as the how many more bytes we need to process the + * current record (this may be 0 if on a record boundary) + */ + size_t received_data(const byte buf[], size_t buf_size); + + /** + * Inject TLS traffic received from counterparty + * @return a hint as the how many more bytes we need to process the + * current record (this may be 0 if on a record boundary) + */ + size_t received_data(const std::vector& buf); + + /** + * Inject plaintext intended for counterparty + */ + void send(const byte buf[], size_t buf_size); + + /** + * Inject plaintext intended for counterparty + */ + void send(const std::string& val); + + /** + * Inject plaintext intended for counterparty + */ + template + void send(const std::vector& val) + { + send(&val[0], val.size()); + } + + /** + * Send a TLS alert message. If the alert is fatal, the internal + * state (keys, etc) will be reset. + * @param alert the Alert to send + */ + void send_alert(const Alert& alert); + + /** + * Send a warning alert + */ + void send_warning_alert(Alert::Type type) { send_alert(Alert(type, false)); } + + /** + * Send a fatal alert + */ + void send_fatal_alert(Alert::Type type) { send_alert(Alert(type, true)); } + + /** + * Send a close notification alert + */ + void close() { send_warning_alert(Alert::CLOSE_NOTIFY); } + + /** + * @return true iff the connection is active for sending application data + */ + bool is_active() const; + + /** + * @return true iff the connection has been definitely closed + */ + bool is_closed() const; + + /** + * Attempt to renegotiate the session + * @param force_full_renegotiation if true, require a full renegotiation, + * otherwise allow session resumption + */ + void renegotiate(bool force_full_renegotiation = false); + + /** + * @return true iff the peer supports heartbeat messages + */ + bool peer_supports_heartbeats() const; + + /** + * @return true iff we are allowed to send heartbeat messages + */ + bool heartbeat_sending_allowed() const; + + /** + * @return true iff the counterparty supports the secure + * renegotiation extensions. + */ + bool secure_renegotiation_supported() const; + + /** + * Attempt to send a heartbeat message (if negotiated with counterparty) + * @param payload will be echoed back + * @param payload_size size of payload in bytes + */ + void heartbeat(const byte payload[], size_t payload_size); + + /** + * Attempt to send a heartbeat message (if negotiated with counterparty) + */ + void heartbeat() { heartbeat(nullptr, 0); } + + /** + * @return certificate chain of the peer (may be empty) + */ + std::vector peer_cert_chain() const; + + /** + * Key material export (RFC 5705) + * @param label a disambiguating label string + * @param context a per-association context value + * @param length the length of the desired key in bytes + * @return key of length bytes + */ + SymmetricKey key_material_export(const std::string& label, + const std::string& context, + size_t length) const; + + Channel(std::function socket_output_fn, + std::function data_cb, + std::function alert_cb, + std::function handshake_cb, + Session_Manager& session_manager, + RandomNumberGenerator& rng, + size_t reserved_io_buffer_size); + + Channel(const Channel&) = delete; + + Channel& operator=(const Channel&) = delete; + + virtual ~Channel(); + protected: + + virtual void process_handshake_msg(const Handshake_State* active_state, + Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents) = 0; + + virtual void initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) = 0; + + virtual std::vector + get_peer_cert_chain(const Handshake_State& state) const = 0; + + virtual Handshake_State* new_handshake_state(class Handshake_IO* io) = 0; + + Handshake_State& create_handshake_state(Protocol_Version version); + + void activate_session(); + + void change_cipher_spec_reader(Connection_Side side); + + void change_cipher_spec_writer(Connection_Side side); + + /* secure renegotiation handling */ + + void secure_renegotiation_check(const class Client_Hello* client_hello); + void secure_renegotiation_check(const class Server_Hello* server_hello); + + std::vector secure_renegotiation_data_for_client_hello() const; + std::vector secure_renegotiation_data_for_server_hello() const; + + RandomNumberGenerator& rng() { return m_rng; } + + Session_Manager& session_manager() { return m_session_manager; } + + bool save_session(const Session& session) const { return m_handshake_cb(session); } + + private: + size_t maximum_fragment_size() const; + + void send_record(byte record_type, const std::vector& record); + + void send_record_under_epoch(u16bit epoch, byte record_type, + const std::vector& record); + + void send_record_array(u16bit epoch, byte record_type, + const byte input[], size_t length); + + void write_record(Connection_Cipher_State* cipher_state, + byte type, const byte input[], size_t length); + + Connection_Sequence_Numbers& sequence_numbers() const; + + std::shared_ptr read_cipher_state_epoch(u16bit epoch) const; + + std::shared_ptr write_cipher_state_epoch(u16bit epoch) const; + + void reset_state(); + + const Handshake_State* active_state() const { return m_active_state.get(); } + + const Handshake_State* pending_state() const { return m_pending_state.get(); } + + /* callbacks */ + std::function m_handshake_cb; + std::function m_data_cb; + std::function m_alert_cb; + std::function m_output_fn; + + /* external state */ + RandomNumberGenerator& m_rng; + Session_Manager& m_session_manager; + + /* sequence number state */ + std::unique_ptr m_sequence_numbers; + + /* pending and active connection states */ + std::unique_ptr m_active_state; + std::unique_ptr m_pending_state; + + /* cipher states for each epoch - epoch 0 is plaintext, thus null cipher state */ + std::map> m_write_cipher_states = + { { 0, nullptr } }; + std::map> m_read_cipher_states = + { { 0, nullptr } }; + + /* I/O buffers */ + secure_vector m_writebuf; + secure_vector m_readbuf; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_ciphersuite.cpp b/src/lib/tls/tls_ciphersuite.cpp new file mode 100644 index 000000000..e8c551b01 --- /dev/null +++ b/src/lib/tls/tls_ciphersuite.cpp @@ -0,0 +1,236 @@ +/* +* TLS Cipher Suite +* (C) 2004-2010,2012,2013 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +/* +* This way all work happens at the constuctor call, and we can +* rely on that happening only once in C++11. +*/ +std::vector gather_known_ciphersuites() + { + std::vector ciphersuites; + + for(size_t i = 0; i <= 0xFFFF; ++i) + { + Ciphersuite suite = Ciphersuite::by_id(i); + + if(suite.valid()) + ciphersuites.push_back(suite); + } + + return ciphersuites; + } + +} + +const std::vector& Ciphersuite::all_known_ciphersuites() + { + static std::vector all_ciphersuites(gather_known_ciphersuites()); + return all_ciphersuites; + } + +Ciphersuite Ciphersuite::by_name(const std::string& name) + { + for(auto suite : all_known_ciphersuites()) + { + if(suite.to_string() == name) + return suite; + } + + return Ciphersuite(); // some unknown ciphersuite + } + +Ciphersuite::Ciphersuite(u16bit ciphersuite_code, + const char* sig_algo, + const char* kex_algo, + const char* cipher_algo, + size_t cipher_keylen, + size_t cipher_ivlen, + const char* mac_algo, + size_t mac_keylen, + const char* prf_algo) : + m_ciphersuite_code(ciphersuite_code), + m_sig_algo(sig_algo), + m_kex_algo(kex_algo), + m_cipher_algo(cipher_algo), + m_mac_algo(mac_algo), + m_prf_algo(prf_algo), + m_cipher_keylen(cipher_keylen), + m_cipher_ivlen(cipher_ivlen), + m_mac_keylen(mac_keylen) + { + } + +bool Ciphersuite::psk_ciphersuite() const + { + return (kex_algo() == "PSK" || + kex_algo() == "DHE_PSK" || + kex_algo() == "ECDHE_PSK"); + } + +bool Ciphersuite::ecc_ciphersuite() const + { + return (sig_algo() == "ECDSA" || kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK"); + } + +bool Ciphersuite::valid() const + { + if(!m_cipher_keylen) // uninitialized object + return false; + + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(!af.prototype_hash_function(prf_algo())) + return false; + + if(mac_algo() == "AEAD") + { + auto cipher_and_mode = split_on(cipher_algo(), '/'); + BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); + if(!af.prototype_block_cipher(cipher_and_mode[0])) + return false; + + const auto mode = cipher_and_mode[1]; + +#if !defined(BOTAN_HAS_AEAD_CCM) + if(mode == "CCM" || mode == "CCM-8") + return false; +#endif + +#if !defined(BOTAN_HAS_AEAD_GCM) + if(mode == "GCM") + return false; +#endif + +#if !defined(BOTAN_HAS_AEAD_OCB) + if(mode == "OCB") + return false; +#endif + } + else + { + if(!af.prototype_block_cipher(cipher_algo()) && + !af.prototype_stream_cipher(cipher_algo())) + return false; + + if(!af.prototype_hash_function(mac_algo())) + return false; + } + + if(kex_algo() == "SRP_SHA") + { +#if !defined(BOTAN_HAS_SRP6) + return false; +#endif + } + else if(kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK") + { +#if !defined(BOTAN_HAS_ECDH) + return false; +#endif + } + else if(kex_algo() == "DH" || kex_algo() == "DHE_PSK") + { +#if !defined(BOTAN_HAS_DIFFIE_HELLMAN) + return false; +#endif + } + + if(sig_algo() == "DSA") + { +#if !defined(BOTAN_HAS_DSA) + return false; +#endif + } + else if(sig_algo() == "ECDSA") + { +#if !defined(BOTAN_HAS_ECDSA) + return false; +#endif + } + else if(sig_algo() == "RSA") + { +#if !defined(BOTAN_HAS_RSA) + return false; +#endif + } + + return true; + } + +std::string Ciphersuite::to_string() const + { + if(m_cipher_keylen == 0) + throw std::runtime_error("Ciphersuite::to_string - no value set"); + + std::ostringstream out; + + out << "TLS_"; + + if(kex_algo() != "RSA") + { + if(kex_algo() == "DH") + out << "DHE"; + else if(kex_algo() == "ECDH") + out << "ECDHE"; + else + out << kex_algo(); + + out << '_'; + } + + if(sig_algo() == "DSA") + out << "DSS_"; + else if(sig_algo() != "") + out << sig_algo() << '_'; + + out << "WITH_"; + + if(cipher_algo() == "RC4") + { + out << "RC4_128_"; + } + else + { + if(cipher_algo() == "3DES") + out << "3DES_EDE"; + else if(cipher_algo().find("Camellia") == 0) + out << "CAMELLIA_" << std::to_string(8*cipher_keylen()); + else + out << replace_chars(cipher_algo(), {'-', '/'}, '_'); + + if(cipher_algo().find("/") != std::string::npos) + out << "_"; // some explicit mode already included + else + out << "_CBC_"; + } + + if(mac_algo() == "SHA-1") + out << "SHA"; + else if(mac_algo() == "AEAD") + out << erase_chars(prf_algo(), {'-'}); + else + out << erase_chars(mac_algo(), {'-'}); + + return out.str(); + } + +} + +} + diff --git a/src/lib/tls/tls_ciphersuite.h b/src/lib/tls/tls_ciphersuite.h new file mode 100644 index 000000000..865e66abb --- /dev/null +++ b/src/lib/tls/tls_ciphersuite.h @@ -0,0 +1,137 @@ +/* +* TLS Cipher Suites +* (C) 2004-2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_CIPHER_SUITES_H__ +#define BOTAN_TLS_CIPHER_SUITES_H__ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Ciphersuite Information +*/ +class BOTAN_DLL Ciphersuite + { + public: + /** + * Convert an SSL/TLS ciphersuite to algorithm fields + * @param suite the ciphersuite code number + * @return ciphersuite object + */ + static Ciphersuite by_id(u16bit suite); + + /** + * Lookup a ciphersuite by name + * @param name the name (eg TLS_RSA_WITH_RC4_128_SHA) + * @return ciphersuite object + */ + static Ciphersuite by_name(const std::string& name); + + /** + * Generate a static list of all known ciphersuites and return it. + * + * @return list of all known ciphersuites + */ + static const std::vector& all_known_ciphersuites(); + + /** + * Formats the ciphersuite back to an RFC-style ciphersuite string + * @return RFC ciphersuite string identifier + */ + std::string to_string() const; + + /** + * @return ciphersuite number + */ + u16bit ciphersuite_code() const { return m_ciphersuite_code; } + + /** + * @return true if this is a PSK ciphersuite + */ + bool psk_ciphersuite() const; + + /** + * @return true if this is an ECC ciphersuite + */ + bool ecc_ciphersuite() const; + + /** + * @return key exchange algorithm used by this ciphersuite + */ + std::string kex_algo() const { return m_kex_algo; } + + /** + * @return signature algorithm used by this ciphersuite + */ + std::string sig_algo() const { return m_sig_algo; } + + /** + * @return symmetric cipher algorithm used by this ciphersuite + */ + std::string cipher_algo() const { return m_cipher_algo; } + + /** + * @return message authentication algorithm used by this ciphersuite + */ + std::string mac_algo() const { return m_mac_algo; } + + std::string prf_algo() const + { + return (m_prf_algo != "") ? m_prf_algo : m_mac_algo; + } + + /** + * @return cipher key length used by this ciphersuite + */ + size_t cipher_keylen() const { return m_cipher_keylen; } + + size_t cipher_ivlen() const { return m_cipher_ivlen; } + + size_t mac_keylen() const { return m_mac_keylen; } + + /** + * @return true if this is a valid/known ciphersuite + */ + bool valid() const; + + Ciphersuite() {} + + private: + + Ciphersuite(u16bit ciphersuite_code, + const char* sig_algo, + const char* kex_algo, + const char* cipher_algo, + size_t cipher_keylen, + size_t cipher_ivlen, + const char* mac_algo, + size_t mac_keylen, + const char* prf_algo = ""); + + u16bit m_ciphersuite_code = 0; + + std::string m_sig_algo; + std::string m_kex_algo; + std::string m_cipher_algo; + std::string m_mac_algo; + std::string m_prf_algo; + + size_t m_cipher_keylen = 0; + size_t m_cipher_ivlen = 0; + size_t m_mac_keylen = 0; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp new file mode 100644 index 000000000..f17247c16 --- /dev/null +++ b/src/lib/tls/tls_client.cpp @@ -0,0 +1,530 @@ +/* +* TLS Client +* (C) 2004-2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +class Client_Handshake_State : public Handshake_State + { + public: + // using Handshake_State::Handshake_State; + + Client_Handshake_State(Handshake_IO* io, + std::function msg_callback = + std::function()) : + Handshake_State(io, msg_callback) {} + + const Public_Key& get_server_public_Key() const + { + BOTAN_ASSERT(server_public_key, "Server sent us a certificate"); + return *server_public_key.get(); + } + + // Used during session resumption + secure_vector resume_master_secret; + + std::unique_ptr server_public_key; + + // Used by client using NPN + std::function)> client_npn_cb; + }; + +} + +/* +* TLS Client Constructor +*/ +Client::Client(std::function output_fn, + std::function proc_cb, + std::function alert_cb, + std::function handshake_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& info, + const Protocol_Version offer_version, + std::function)> next_protocol, + size_t io_buf_sz) : + Channel(output_fn, proc_cb, alert_cb, handshake_cb, session_manager, rng, io_buf_sz), + m_policy(policy), + m_creds(creds), + m_info(info) + { + const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname()); + + Handshake_State& state = create_handshake_state(offer_version); + send_client_hello(state, false, offer_version, srp_identifier, next_protocol); + } + +Handshake_State* Client::new_handshake_state(Handshake_IO* io) + { + return new Client_Handshake_State(io); + } + +std::vector +Client::get_peer_cert_chain(const Handshake_State& state) const + { + if(state.server_certs()) + return state.server_certs()->cert_chain(); + return std::vector(); + } + +/* +* Send a new client hello to renegotiate +*/ +void Client::initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) + { + send_client_hello(state, + force_full_renegotiation, + state.version()); + } + +void Client::send_client_hello(Handshake_State& state_base, + bool force_full_renegotiation, + Protocol_Version version, + const std::string& srp_identifier, + std::function)> next_protocol) + { + Client_Handshake_State& state = dynamic_cast(state_base); + + if(state.version().is_datagram_protocol()) + state.set_expected_next(HELLO_VERIFY_REQUEST); // optional + state.set_expected_next(SERVER_HELLO); + + state.client_npn_cb = next_protocol; + + const bool send_npn_request = static_cast(next_protocol); + + if(!force_full_renegotiation && !m_info.empty()) + { + Session session_info; + if(session_manager().load_from_server_info(m_info, session_info)) + { + if(srp_identifier == "" || session_info.srp_identifier() == srp_identifier) + { + state.client_hello(new Client_Hello( + state.handshake_io(), + state.hash(), + m_policy, + rng(), + secure_renegotiation_data_for_client_hello(), + session_info, + send_npn_request)); + + state.resume_master_secret = session_info.master_secret(); + } + } + } + + if(!state.client_hello()) // not resuming + { + state.client_hello(new Client_Hello( + state.handshake_io(), + state.hash(), + version, + m_policy, + rng(), + secure_renegotiation_data_for_client_hello(), + send_npn_request, + m_info.hostname(), + srp_identifier)); + } + + secure_renegotiation_check(state.client_hello()); + } + +/* +* Process a handshake message +*/ +void Client::process_handshake_msg(const Handshake_State* active_state, + Handshake_State& state_base, + Handshake_Type type, + const std::vector& contents) + { + Client_Handshake_State& state = dynamic_cast(state_base); + + if(type == HELLO_REQUEST && active_state) + { + Hello_Request hello_request(contents); + + // Ignore request entirely if we are currently negotiating a handshake + if(state.client_hello()) + return; + + if(!m_policy.allow_server_initiated_renegotiation() || + (!m_policy.allow_insecure_renegotiation() && !secure_renegotiation_supported())) + { + // RFC 5746 section 4.2 + send_warning_alert(Alert::NO_RENEGOTIATION); + return; + } + + this->initiate_handshake(state, false); + + return; + } + + state.confirm_transition_to(type); + + if(type != HANDSHAKE_CCS && type != FINISHED && type != HELLO_VERIFY_REQUEST) + state.hash().update(state.handshake_io().format(contents, type)); + + if(type == HELLO_VERIFY_REQUEST) + { + state.set_expected_next(SERVER_HELLO); + state.set_expected_next(HELLO_VERIFY_REQUEST); // might get it again + + Hello_Verify_Request hello_verify_request(contents); + + state.hello_verify_request(hello_verify_request); + } + else if(type == SERVER_HELLO) + { + state.server_hello(new Server_Hello(contents)); + + if(!state.client_hello()->offered_suite(state.server_hello()->ciphersuite())) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with ciphersuite we didn't send"); + } + + if(!value_exists(state.client_hello()->compression_methods(), + state.server_hello()->compression_method())) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with compression method we didn't send"); + } + + if(!state.client_hello()->next_protocol_notification() && + state.server_hello()->next_protocol_notification()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent next protocol but we didn't request it"); + } + + if(state.server_hello()->supports_session_ticket()) + { + if(!state.client_hello()->supports_session_ticket()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent session ticket extension but we did not"); + } + + state.set_version(state.server_hello()->version()); + + secure_renegotiation_check(state.server_hello()); + + const bool server_returned_same_session_id = + !state.server_hello()->session_id().empty() && + (state.server_hello()->session_id() == state.client_hello()->session_id()); + + if(server_returned_same_session_id) + { + // successful resumption + + /* + * In this case, we offered the version used in the original + * session, and the server must resume with the same version. + */ + if(state.server_hello()->version() != state.client_hello()->version()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server resumed session but with wrong version"); + + state.compute_session_keys(state.resume_master_secret); + + if(state.server_hello()->supports_session_ticket()) + state.set_expected_next(NEW_SESSION_TICKET); + else + state.set_expected_next(HANDSHAKE_CCS); + } + else + { + // new session + + if(state.client_hello()->version().is_datagram_protocol() != + state.server_hello()->version().is_datagram_protocol()) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Server replied with different protocol type than we offered"); + } + + if(state.version() > state.client_hello()->version()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with later version than in hello"); + } + + if(!m_policy.acceptable_protocol_version(state.version())) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Server version is unacceptable by policy"); + } + + if(state.ciphersuite().sig_algo() != "") + { + state.set_expected_next(CERTIFICATE); + } + else if(state.ciphersuite().kex_algo() == "PSK") + { + /* PSK is anonymous so no certificate/cert req message is + ever sent. The server may or may not send a server kex, + depending on if it has an identity hint for us. + + (EC)DHE_PSK always sends a server key exchange for the + DH exchange portion. + */ + + state.set_expected_next(SERVER_KEX); + state.set_expected_next(SERVER_HELLO_DONE); + } + else if(state.ciphersuite().kex_algo() != "RSA") + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } + } + } + else if(type == CERTIFICATE) + { + if(state.ciphersuite().kex_algo() != "RSA") + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } + + state.server_certs(new Certificate(contents)); + + const std::vector& server_certs = + state.server_certs()->cert_chain(); + + if(server_certs.empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client: No certificates sent by server"); + + try + { + m_creds.verify_certificate_chain("tls-client", m_info.hostname(), server_certs); + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); + } + + std::unique_ptr peer_key(server_certs[0].subject_public_key()); + + if(peer_key->algo_name() != state.ciphersuite().sig_algo()) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Certificate key type did not match ciphersuite"); + + state.server_public_key.reset(peer_key.release()); + } + else if(type == SERVER_KEX) + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + + state.server_kex( + new Server_Key_Exchange(contents, + state.ciphersuite().kex_algo(), + state.ciphersuite().sig_algo(), + state.version()) + ); + + if(state.ciphersuite().sig_algo() != "") + { + const Public_Key& server_key = state.get_server_public_Key(); + + if(!state.server_kex()->verify(server_key, state)) + { + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Bad signature on server key exchange"); + } + } + } + else if(type == CERTIFICATE_REQUEST) + { + state.set_expected_next(SERVER_HELLO_DONE); + state.cert_req( + new Certificate_Req(contents, state.version()) + ); + } + else if(type == SERVER_HELLO_DONE) + { + state.server_hello_done( + new Server_Hello_Done(contents) + ); + + if(state.received_handshake_msg(CERTIFICATE_REQUEST)) + { + const std::vector& types = + state.cert_req()->acceptable_cert_types(); + + std::vector client_certs = + m_creds.cert_chain(types, + "tls-client", + m_info.hostname()); + + state.client_certs( + new Certificate(state.handshake_io(), + state.hash(), + client_certs) + ); + } + + state.client_kex( + new Client_Key_Exchange(state.handshake_io(), + state, + m_policy, + m_creds, + state.server_public_key.get(), + m_info.hostname(), + rng()) + ); + + state.compute_session_keys(); + + if(state.received_handshake_msg(CERTIFICATE_REQUEST) && + !state.client_certs()->empty()) + { + Private_Key* private_key = + m_creds.private_key_for(state.client_certs()->cert_chain()[0], + "tls-client", + m_info.hostname()); + + state.client_verify( + new Certificate_Verify(state.handshake_io(), + state, + m_policy, + rng(), + private_key) + ); + } + + state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(CLIENT); + + if(state.server_hello()->next_protocol_notification()) + { + const std::string protocol = state.client_npn_cb( + state.server_hello()->next_protocols()); + + state.next_protocol( + new Next_Protocol(state.handshake_io(), state.hash(), protocol) + ); + } + + state.client_finished( + new Finished(state.handshake_io(), state, CLIENT) + ); + + if(state.server_hello()->supports_session_ticket()) + state.set_expected_next(NEW_SESSION_TICKET); + else + state.set_expected_next(HANDSHAKE_CCS); + } + else if(type == NEW_SESSION_TICKET) + { + state.new_session_ticket(new New_Session_Ticket(contents)); + + state.set_expected_next(HANDSHAKE_CCS); + } + else if(type == HANDSHAKE_CCS) + { + state.set_expected_next(FINISHED); + + change_cipher_spec_reader(CLIENT); + } + else if(type == FINISHED) + { + state.server_finished(new Finished(contents)); + + if(!state.server_finished()->verify(state, SERVER)) + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Finished message didn't verify"); + + state.hash().update(state.handshake_io().format(contents, type)); + + if(!state.client_finished()) // session resume case + { + state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(CLIENT); + + if(state.server_hello()->next_protocol_notification()) + { + const std::string protocol = state.client_npn_cb( + state.server_hello()->next_protocols()); + + state.next_protocol( + new Next_Protocol(state.handshake_io(), state.hash(), protocol) + ); + } + + state.client_finished( + new Finished(state.handshake_io(), state, CLIENT) + ); + } + + std::vector session_id = state.server_hello()->session_id(); + + const std::vector& session_ticket = state.session_ticket(); + + if(session_id.empty() && !session_ticket.empty()) + session_id = make_hello_random(rng()); + + Session session_info( + session_id, + state.session_keys().master_secret(), + state.server_hello()->version(), + state.server_hello()->ciphersuite(), + state.server_hello()->compression_method(), + CLIENT, + state.server_hello()->fragment_size(), + get_peer_cert_chain(state), + session_ticket, + m_info, + "" + ); + + const bool should_save = save_session(session_info); + + if(!session_id.empty()) + { + if(should_save) + session_manager().save(session_info); + else + session_manager().remove_entry(session_info.session_id()); + } + + activate_session(); + } + else + throw Unexpected_Message("Unknown handshake message received"); + } + +} + +} diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h new file mode 100644 index 000000000..c4440c7ac --- /dev/null +++ b/src/lib/tls/tls_client.h @@ -0,0 +1,106 @@ +/* +* TLS Client +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_CLIENT_H__ +#define BOTAN_TLS_CLIENT_H__ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* SSL/TLS Client +*/ +class BOTAN_DLL Client : public Channel + { + public: + /** + * Set up a new TLS client session + * + * @param socket_output_fn is called with data for the outbound socket + * + * @param proc_cb is called when new application data is received + * + * @param alert_cb is called when a TLS alert is received + * + * @param handshake_cb is called when a handshake is completed + * + * @param session_manager manages session state + * + * @param creds manages application/user credentials + * + * @param policy specifies other connection policy information + * + * @param rng a random number generator + * + * @param server_info is identifying information about the TLS server + * + * @param offer_version specifies which version we will offer + * to the TLS server. + * + * @param next_protocol allows the client to specify what the next + * protocol will be. For more information read + * http://technotes.googlecode.com/git/nextprotoneg.html. + * + * If the function is not empty, NPN will be negotiated + * and if the server supports NPN the function will be + * called with the list of protocols the server advertised; + * the client should return the protocol it would like to use. + * + * @param reserved_io_buffer_size This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. + */ + Client(std::function socket_output_fn, + std::function data_cb, + std::function alert_cb, + std::function handshake_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version offer_version = Protocol_Version::latest_tls_version(), + std::function)> next_protocol = + std::function)>(), + size_t reserved_io_buffer_size = 16*1024 + ); + private: + std::vector + get_peer_cert_chain(const Handshake_State& state) const override; + + void initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) override; + + void send_client_hello(Handshake_State& state, + bool force_full_renegotiation, + Protocol_Version version, + const std::string& srp_identifier = "", + std::function)> next_protocol = + std::function)>()); + + void process_handshake_msg(const Handshake_State* active_state, + Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents) override; + + Handshake_State* new_handshake_state(Handshake_IO* io) override; + + const Policy& m_policy; + Credentials_Manager& m_creds; + const Server_Information m_info; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_exceptn.h b/src/lib/tls/tls_exceptn.h new file mode 100644 index 000000000..529d1f315 --- /dev/null +++ b/src/lib/tls/tls_exceptn.h @@ -0,0 +1,47 @@ +/* +* Exceptions +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_EXCEPTION_H__ +#define BOTAN_TLS_EXCEPTION_H__ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Exception Base Class +*/ +class BOTAN_DLL TLS_Exception : public Exception + { + public: + Alert::Type type() const noexcept { return alert_type; } + + TLS_Exception(Alert::Type type, + const std::string& err_msg = "Unknown error") : + Exception(err_msg), alert_type(type) {} + + private: + Alert::Type alert_type; + }; + +/** +* Unexpected_Message Exception +*/ +struct BOTAN_DLL Unexpected_Message : public TLS_Exception + { + Unexpected_Message(const std::string& err) : + TLS_Exception(Alert::UNEXPECTED_MESSAGE, err) {} + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp new file mode 100644 index 000000000..1ae9f1749 --- /dev/null +++ b/src/lib/tls/tls_extensions.cpp @@ -0,0 +1,533 @@ +/* +* TLS Extensions +* (C) 2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +Extension* make_extension(TLS_Data_Reader& reader, + u16bit code, + u16bit size) + { + switch(code) + { + case TLSEXT_SERVER_NAME_INDICATION: + return new Server_Name_Indicator(reader, size); + + case TLSEXT_MAX_FRAGMENT_LENGTH: + return new Maximum_Fragment_Length(reader, size); + + case TLSEXT_SRP_IDENTIFIER: + return new SRP_Identifier(reader, size); + + case TLSEXT_USABLE_ELLIPTIC_CURVES: + return new Supported_Elliptic_Curves(reader, size); + + case TLSEXT_SAFE_RENEGOTIATION: + return new Renegotiation_Extension(reader, size); + + case TLSEXT_SIGNATURE_ALGORITHMS: + return new Signature_Algorithms(reader, size); + + case TLSEXT_NEXT_PROTOCOL: + return new Next_Protocol_Notification(reader, size); + + case TLSEXT_HEARTBEAT_SUPPORT: + return new Heartbeat_Support_Indicator(reader, size); + + case TLSEXT_SESSION_TICKET: + return new Session_Ticket(reader, size); + + default: + return nullptr; // not known + } + } + +} + +void Extensions::deserialize(TLS_Data_Reader& reader) + { + if(reader.has_remaining()) + { + const u16bit all_extn_size = reader.get_u16bit(); + + if(reader.remaining_bytes() != all_extn_size) + throw Decoding_Error("Bad extension size"); + + while(reader.has_remaining()) + { + const u16bit extension_code = reader.get_u16bit(); + const u16bit extension_size = reader.get_u16bit(); + + Extension* extn = make_extension(reader, + extension_code, + extension_size); + + if(extn) + this->add(extn); + else // unknown/unhandled extension + reader.discard_next(extension_size); + } + } + } + +std::vector Extensions::serialize() const + { + std::vector buf(2); // 2 bytes for length field + + for(auto& extn : extensions) + { + if(extn.second->empty()) + continue; + + const u16bit extn_code = extn.second->type(); + + std::vector extn_val = extn.second->serialize(); + + buf.push_back(get_byte(0, extn_code)); + buf.push_back(get_byte(1, extn_code)); + + buf.push_back(get_byte(0, extn_val.size())); + buf.push_back(get_byte(1, extn_val.size())); + + buf += extn_val; + } + + const u16bit extn_size = buf.size() - 2; + + buf[0] = get_byte(0, extn_size); + buf[1] = get_byte(1, extn_size); + + // avoid sending a completely empty extensions block + if(buf.size() == 2) + return std::vector(); + + return buf; + } + +Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader, + u16bit extension_size) + { + /* + * This is used by the server to confirm that it knew the name + */ + if(extension_size == 0) + return; + + u16bit name_bytes = reader.get_u16bit(); + + if(name_bytes + 2 != extension_size) + throw Decoding_Error("Bad encoding of SNI extension"); + + while(name_bytes) + { + byte name_type = reader.get_byte(); + name_bytes--; + + if(name_type == 0) // DNS + { + sni_host_name = reader.get_string(2, 1, 65535); + name_bytes -= (2 + sni_host_name.size()); + } + else // some other unknown name type + { + reader.discard_next(name_bytes); + name_bytes = 0; + } + } + } + +std::vector Server_Name_Indicator::serialize() const + { + std::vector buf; + + size_t name_len = sni_host_name.size(); + + buf.push_back(get_byte(0, name_len+3)); + buf.push_back(get_byte(1, name_len+3)); + buf.push_back(0); // DNS + + buf.push_back(get_byte(0, name_len)); + buf.push_back(get_byte(1, name_len)); + + buf += std::make_pair( + reinterpret_cast(sni_host_name.data()), + sni_host_name.size()); + + return buf; + } + +SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader, + u16bit extension_size) + { + srp_identifier = reader.get_string(1, 1, 255); + + if(srp_identifier.size() + 1 != extension_size) + throw Decoding_Error("Bad encoding for SRP identifier extension"); + } + +std::vector SRP_Identifier::serialize() const + { + std::vector buf; + + const byte* srp_bytes = + reinterpret_cast(srp_identifier.data()); + + append_tls_length_value(buf, srp_bytes, srp_identifier.size(), 1); + + return buf; + } + +Renegotiation_Extension::Renegotiation_Extension(TLS_Data_Reader& reader, + u16bit extension_size) + { + reneg_data = reader.get_range(1, 0, 255); + + if(reneg_data.size() + 1 != extension_size) + throw Decoding_Error("Bad encoding for secure renegotiation extn"); + } + +std::vector Renegotiation_Extension::serialize() const + { + std::vector buf; + append_tls_length_value(buf, reneg_data, 1); + return buf; + } + +std::vector Maximum_Fragment_Length::serialize() const + { + const std::map fragment_to_code = { { 512, 1 }, + { 1024, 2 }, + { 2048, 3 }, + { 4096, 4 } }; + + auto i = fragment_to_code.find(m_max_fragment); + + if(i == fragment_to_code.end()) + throw std::invalid_argument("Bad setting " + + std::to_string(m_max_fragment) + + " for maximum fragment size"); + + return std::vector(1, i->second); + } + +Maximum_Fragment_Length::Maximum_Fragment_Length(TLS_Data_Reader& reader, + u16bit extension_size) + { + if(extension_size != 1) + throw Decoding_Error("Bad size for maximum fragment extension"); + byte val = reader.get_byte(); + + const std::map code_to_fragment = { { 1, 512 }, + { 2, 1024 }, + { 3, 2048 }, + { 4, 4096 } }; + + auto i = code_to_fragment.find(val); + + if(i == code_to_fragment.end()) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Bad value in maximum fragment extension"); + + m_max_fragment = i->second; + } + +Next_Protocol_Notification::Next_Protocol_Notification(TLS_Data_Reader& reader, + u16bit extension_size) + { + if(extension_size == 0) + return; // empty extension + + size_t bytes_remaining = extension_size; + + while(bytes_remaining) + { + const std::string p = reader.get_string(1, 0, 255); + + if(bytes_remaining < p.size() + 1) + throw Decoding_Error("Bad encoding for next protocol extension"); + + bytes_remaining -= (p.size() + 1); + + m_protocols.push_back(p); + } + } + +std::vector Next_Protocol_Notification::serialize() const + { + std::vector buf; + + for(size_t i = 0; i != m_protocols.size(); ++i) + { + const std::string p = m_protocols[i]; + + if(p != "") + append_tls_length_value(buf, + reinterpret_cast(p.data()), + p.size(), + 1); + } + + return buf; + } + +std::string Supported_Elliptic_Curves::curve_id_to_name(u16bit id) + { + switch(id) + { + case 15: + return "secp160k1"; + case 16: + return "secp160r1"; + case 17: + return "secp160r2"; + case 18: + return "secp192k1"; + case 19: + return "secp192r1"; + case 20: + return "secp224k1"; + case 21: + return "secp224r1"; + case 22: + return "secp256k1"; + case 23: + return "secp256r1"; + case 24: + return "secp384r1"; + case 25: + return "secp521r1"; + case 26: + return "brainpool256r1"; + case 27: + return "brainpool384r1"; + case 28: + return "brainpool512r1"; + default: + return ""; // something we don't know or support + } + } + +u16bit Supported_Elliptic_Curves::name_to_curve_id(const std::string& name) + { + if(name == "secp160k1") + return 15; + if(name == "secp160r1") + return 16; + if(name == "secp160r2") + return 17; + if(name == "secp192k1") + return 18; + if(name == "secp192r1") + return 19; + if(name == "secp224k1") + return 20; + if(name == "secp224r1") + return 21; + if(name == "secp256k1") + return 22; + if(name == "secp256r1") + return 23; + if(name == "secp384r1") + return 24; + if(name == "secp521r1") + return 25; + if(name == "brainpool256r1") + return 26; + if(name == "brainpool384r1") + return 27; + if(name == "brainpool512r1") + return 28; + + throw Invalid_Argument("name_to_curve_id unknown name " + name); + } + +std::vector Supported_Elliptic_Curves::serialize() const + { + std::vector buf(2); + + for(size_t i = 0; i != m_curves.size(); ++i) + { + const u16bit id = name_to_curve_id(m_curves[i]); + buf.push_back(get_byte(0, id)); + buf.push_back(get_byte(1, id)); + } + + buf[0] = get_byte(0, buf.size()-2); + buf[1] = get_byte(1, buf.size()-2); + + return buf; + } + +Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, + u16bit extension_size) + { + u16bit len = reader.get_u16bit(); + + if(len + 2 != extension_size) + throw Decoding_Error("Inconsistent length field in elliptic curve list"); + + if(len % 2 == 1) + throw Decoding_Error("Elliptic curve list of strange size"); + + len /= 2; + + for(size_t i = 0; i != len; ++i) + { + const u16bit id = reader.get_u16bit(); + const std::string name = curve_id_to_name(id); + + if(name != "") + m_curves.push_back(name); + } + } + +std::string Signature_Algorithms::hash_algo_name(byte code) + { + switch(code) + { + case 1: + return "MD5"; + // code 1 is MD5 - ignore it + + case 2: + return "SHA-1"; + case 3: + return "SHA-224"; + case 4: + return "SHA-256"; + case 5: + return "SHA-384"; + case 6: + return "SHA-512"; + default: + return ""; + } + } + +byte Signature_Algorithms::hash_algo_code(const std::string& name) + { + if(name == "MD5") + return 1; + + if(name == "SHA-1") + return 2; + + if(name == "SHA-224") + return 3; + + if(name == "SHA-256") + return 4; + + if(name == "SHA-384") + return 5; + + if(name == "SHA-512") + return 6; + + throw Internal_Error("Unknown hash ID " + name + " for signature_algorithms"); + } + +std::string Signature_Algorithms::sig_algo_name(byte code) + { + switch(code) + { + case 1: + return "RSA"; + case 2: + return "DSA"; + case 3: + return "ECDSA"; + default: + return ""; + } + } + +byte Signature_Algorithms::sig_algo_code(const std::string& name) + { + if(name == "RSA") + return 1; + + if(name == "DSA") + return 2; + + if(name == "ECDSA") + return 3; + + throw Internal_Error("Unknown sig ID " + name + " for signature_algorithms"); + } + +std::vector Signature_Algorithms::serialize() const + { + std::vector buf(2); + + for(size_t i = 0; i != m_supported_algos.size(); ++i) + { + try + { + const byte hash_code = hash_algo_code(m_supported_algos[i].first); + const byte sig_code = sig_algo_code(m_supported_algos[i].second); + + buf.push_back(hash_code); + buf.push_back(sig_code); + } + catch(...) + {} + } + + buf[0] = get_byte(0, buf.size()-2); + buf[1] = get_byte(1, buf.size()-2); + + return buf; + } + +Signature_Algorithms::Signature_Algorithms(const std::vector& hashes, + const std::vector& sigs) + { + for(size_t i = 0; i != hashes.size(); ++i) + for(size_t j = 0; j != sigs.size(); ++j) + m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j])); + } + +Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader, + u16bit extension_size) + { + u16bit len = reader.get_u16bit(); + + if(len + 2 != extension_size) + throw Decoding_Error("Bad encoding on signature algorithms extension"); + + while(len) + { + const std::string hash_code = hash_algo_name(reader.get_byte()); + const std::string sig_code = sig_algo_name(reader.get_byte()); + + len -= 2; + + // If not something we know, ignore it completely + if(hash_code == "" || sig_code == "") + continue; + + m_supported_algos.push_back(std::make_pair(hash_code, sig_code)); + } + } + +Session_Ticket::Session_Ticket(TLS_Data_Reader& reader, + u16bit extension_size) + { + m_ticket = reader.get_elem >(extension_size); + } + +} + +} diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h new file mode 100644 index 000000000..de3654fd3 --- /dev/null +++ b/src/lib/tls/tls_extensions.h @@ -0,0 +1,397 @@ +/* +* TLS Extensions +* (C) 2011-2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_EXTENSIONS_H__ +#define BOTAN_TLS_EXTENSIONS_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class TLS_Data_Reader; + +enum Handshake_Extension_Type { + TLSEXT_SERVER_NAME_INDICATION = 0, + TLSEXT_MAX_FRAGMENT_LENGTH = 1, + TLSEXT_CLIENT_CERT_URL = 2, + TLSEXT_TRUSTED_CA_KEYS = 3, + TLSEXT_TRUNCATED_HMAC = 4, + + TLSEXT_CERTIFICATE_TYPES = 9, + TLSEXT_USABLE_ELLIPTIC_CURVES = 10, + TLSEXT_EC_POINT_FORMATS = 11, + TLSEXT_SRP_IDENTIFIER = 12, + TLSEXT_SIGNATURE_ALGORITHMS = 13, + TLSEXT_HEARTBEAT_SUPPORT = 15, + + TLSEXT_SESSION_TICKET = 35, + + TLSEXT_NEXT_PROTOCOL = 13172, + + TLSEXT_SAFE_RENEGOTIATION = 65281, +}; + +/** +* Base class representing a TLS extension of some kind +*/ +class Extension + { + public: + /** + * @return code number of the extension + */ + virtual Handshake_Extension_Type type() const = 0; + + /** + * @return serialized binary for the extension + */ + virtual std::vector serialize() const = 0; + + /** + * @return if we should encode this extension or not + */ + virtual bool empty() const = 0; + + virtual ~Extension() {} + }; + +/** +* Server Name Indicator extension (RFC 3546) +*/ +class Server_Name_Indicator : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SERVER_NAME_INDICATION; } + + Handshake_Extension_Type type() const { return static_type(); } + + Server_Name_Indicator(const std::string& host_name) : + sni_host_name(host_name) {} + + Server_Name_Indicator(TLS_Data_Reader& reader, + u16bit extension_size); + + std::string host_name() const { return sni_host_name; } + + std::vector serialize() const; + + bool empty() const { return sni_host_name == ""; } + private: + std::string sni_host_name; + }; + +/** +* SRP identifier extension (RFC 5054) +*/ +class SRP_Identifier : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SRP_IDENTIFIER; } + + Handshake_Extension_Type type() const { return static_type(); } + + SRP_Identifier(const std::string& identifier) : + srp_identifier(identifier) {} + + SRP_Identifier(TLS_Data_Reader& reader, + u16bit extension_size); + + std::string identifier() const { return srp_identifier; } + + std::vector serialize() const; + + bool empty() const { return srp_identifier == ""; } + private: + std::string srp_identifier; + }; + +/** +* Renegotiation Indication Extension (RFC 5746) +*/ +class Renegotiation_Extension : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SAFE_RENEGOTIATION; } + + Handshake_Extension_Type type() const { return static_type(); } + + Renegotiation_Extension() {} + + Renegotiation_Extension(const std::vector& bits) : + reneg_data(bits) {} + + Renegotiation_Extension(TLS_Data_Reader& reader, + u16bit extension_size); + + const std::vector& renegotiation_info() const + { return reneg_data; } + + std::vector serialize() const; + + bool empty() const { return false; } // always send this + private: + std::vector reneg_data; + }; + +/** +* Maximum Fragment Length Negotiation Extension (RFC 4366 sec 3.2) +*/ +class Maximum_Fragment_Length : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_MAX_FRAGMENT_LENGTH; } + + Handshake_Extension_Type type() const { return static_type(); } + + bool empty() const { return false; } + + size_t fragment_size() const { return m_max_fragment; } + + std::vector serialize() const; + + /** + * @param max_fragment specifies what maximum fragment size to + * advertise. Currently must be one of 512, 1024, 2048, or + * 4096. + */ + Maximum_Fragment_Length(size_t max_fragment) : + m_max_fragment(max_fragment) {} + + Maximum_Fragment_Length(TLS_Data_Reader& reader, + u16bit extension_size); + + private: + size_t m_max_fragment; + }; + +/** +* Next Protocol Negotiation +* http://technotes.googlecode.com/git/nextprotoneg.html +* +* This implementation requires the semantics defined in the Google +* spec (implemented in Chromium); the internet draft leaves the format +* unspecified. +*/ +class Next_Protocol_Notification : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_NEXT_PROTOCOL; } + + Handshake_Extension_Type type() const { return static_type(); } + + const std::vector& protocols() const + { return m_protocols; } + + /** + * Empty extension, used by client + */ + Next_Protocol_Notification() {} + + /** + * List of protocols, used by server + */ + Next_Protocol_Notification(const std::vector& protocols) : + m_protocols(protocols) {} + + Next_Protocol_Notification(TLS_Data_Reader& reader, + u16bit extension_size); + + std::vector serialize() const; + + bool empty() const { return false; } + private: + std::vector m_protocols; + }; + +/** +* Session Ticket Extension (RFC 5077) +*/ +class Session_Ticket : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SESSION_TICKET; } + + Handshake_Extension_Type type() const { return static_type(); } + + /** + * @return contents of the session ticket + */ + const std::vector& contents() const { return m_ticket; } + + /** + * Create empty extension, used by both client and server + */ + Session_Ticket() {} + + /** + * Extension with ticket, used by client + */ + Session_Ticket(const std::vector& session_ticket) : + m_ticket(session_ticket) {} + + /** + * Deserialize a session ticket + */ + Session_Ticket(TLS_Data_Reader& reader, u16bit extension_size); + + std::vector serialize() const { return m_ticket; } + + bool empty() const { return false; } + private: + std::vector m_ticket; + }; + +/** +* Supported Elliptic Curves Extension (RFC 4492) +*/ +class Supported_Elliptic_Curves : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_USABLE_ELLIPTIC_CURVES; } + + Handshake_Extension_Type type() const { return static_type(); } + + static std::string curve_id_to_name(u16bit id); + static u16bit name_to_curve_id(const std::string& name); + + const std::vector& curves() const { return m_curves; } + + std::vector serialize() const; + + Supported_Elliptic_Curves(const std::vector& curves) : + m_curves(curves) {} + + Supported_Elliptic_Curves(TLS_Data_Reader& reader, + u16bit extension_size); + + bool empty() const { return m_curves.empty(); } + private: + std::vector m_curves; + }; + +/** +* Signature Algorithms Extension for TLS 1.2 (RFC 5246) +*/ +class Signature_Algorithms : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SIGNATURE_ALGORITHMS; } + + Handshake_Extension_Type type() const { return static_type(); } + + static std::string hash_algo_name(byte code); + static byte hash_algo_code(const std::string& name); + + static std::string sig_algo_name(byte code); + static byte sig_algo_code(const std::string& name); + + std::vector > + supported_signature_algorthms() const + { + return m_supported_algos; + } + + std::vector serialize() const; + + bool empty() const { return false; } + + Signature_Algorithms(const std::vector& hashes, + const std::vector& sig_algos); + + Signature_Algorithms(const std::vector >& algos) : + m_supported_algos(algos) {} + + Signature_Algorithms(TLS_Data_Reader& reader, + u16bit extension_size); + private: + std::vector > m_supported_algos; + }; + +/** +* Heartbeat Extension (RFC 6520) +*/ +class Heartbeat_Support_Indicator : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_HEARTBEAT_SUPPORT; } + + Handshake_Extension_Type type() const { return static_type(); } + + bool peer_allowed_to_send() const { return m_peer_allowed_to_send; } + + std::vector serialize() const; + + bool empty() const { return false; } + + Heartbeat_Support_Indicator(bool peer_allowed_to_send) : + m_peer_allowed_to_send(peer_allowed_to_send) {} + + Heartbeat_Support_Indicator(TLS_Data_Reader& reader, u16bit extension_size); + + private: + bool m_peer_allowed_to_send; + }; + +/** +* Represents a block of extensions in a hello message +*/ +class Extensions + { + public: + template + T* get() const + { + Handshake_Extension_Type type = T::static_type(); + + auto i = extensions.find(type); + + if(i != extensions.end()) + return dynamic_cast(i->second.get()); + return nullptr; + } + + void add(Extension* extn) + { + extensions[extn->type()].reset(extn); + } + + std::vector serialize() const; + + void deserialize(TLS_Data_Reader& reader); + + Extensions() {} + + Extensions(TLS_Data_Reader& reader) { deserialize(reader); } + + private: + Extensions(const Extensions&) {} + Extensions& operator=(const Extensions&) { return (*this); } + + std::map> extensions; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_handshake_hash.cpp b/src/lib/tls/tls_handshake_hash.cpp new file mode 100644 index 000000000..4e7a0b9b7 --- /dev/null +++ b/src/lib/tls/tls_handshake_hash.cpp @@ -0,0 +1,86 @@ +/* +* TLS Handshake Hash +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Return a TLS Handshake Hash +*/ +secure_vector Handshake_Hash::final(Protocol_Version version, + const std::string& mac_algo) const + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + std::unique_ptr hash; + + if(version.supports_ciphersuite_specific_prf()) + { + if(mac_algo == "MD5" || mac_algo == "SHA-1") + hash.reset(af.make_hash_function("SHA-256")); + else + hash.reset(af.make_hash_function(mac_algo)); + } + else + hash.reset(af.make_hash_function("Parallel(MD5,SHA-160)")); + + hash->update(data); + return hash->final(); + } + +/** +* Return a SSLv3 Handshake Hash +*/ +secure_vector Handshake_Hash::final_ssl3(const secure_vector& secret) const + { + const byte PAD_INNER = 0x36, PAD_OUTER = 0x5C; + + Algorithm_Factory& af = global_state().algorithm_factory(); + + std::unique_ptr md5(af.make_hash_function("MD5")); + std::unique_ptr sha1(af.make_hash_function("SHA-1")); + + md5->update(data); + sha1->update(data); + + md5->update(secret); + sha1->update(secret); + + for(size_t i = 0; i != 48; ++i) + md5->update(PAD_INNER); + for(size_t i = 0; i != 40; ++i) + sha1->update(PAD_INNER); + + secure_vector inner_md5 = md5->final(), inner_sha1 = sha1->final(); + + md5->update(secret); + sha1->update(secret); + + for(size_t i = 0; i != 48; ++i) + md5->update(PAD_OUTER); + for(size_t i = 0; i != 40; ++i) + sha1->update(PAD_OUTER); + + md5->update(inner_md5); + sha1->update(inner_sha1); + + secure_vector output; + output += md5->final(); + output += sha1->final(); + return output; + } + +} + +} diff --git a/src/lib/tls/tls_handshake_hash.h b/src/lib/tls/tls_handshake_hash.h new file mode 100644 index 000000000..840895963 --- /dev/null +++ b/src/lib/tls/tls_handshake_hash.h @@ -0,0 +1,50 @@ +/* +* TLS Handshake Hash +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_HASH_H__ +#define BOTAN_TLS_HANDSHAKE_HASH_H__ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +using namespace Botan; + +/** +* TLS Handshake Hash +*/ +class Handshake_Hash + { + public: + void update(const byte in[], size_t length) + { data += std::make_pair(in, length); } + + void update(const std::vector& in) + { data += in; } + + secure_vector final(Protocol_Version version, + const std::string& mac_algo) const; + + secure_vector final_ssl3(const secure_vector& master_secret) const; + + const std::vector& get_contents() const + { return data; } + + void reset() { data.clear(); } + private: + std::vector data; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_handshake_io.cpp b/src/lib/tls/tls_handshake_io.cpp new file mode 100644 index 000000000..38def13a2 --- /dev/null +++ b/src/lib/tls/tls_handshake_io.cpp @@ -0,0 +1,381 @@ +/* +* TLS Handshake IO +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +inline size_t load_be24(const byte q[3]) + { + return make_u32bit(0, + q[0], + q[1], + q[2]); + } + +void store_be24(byte out[3], size_t val) + { + out[0] = get_byte(1, val); + out[1] = get_byte(2, val); + out[2] = get_byte(3, val); + } + +} + +Protocol_Version Stream_Handshake_IO::initial_record_version() const + { + return Protocol_Version::TLS_V10; + } + +void Stream_Handshake_IO::add_record(const std::vector& record, + Record_Type record_type, u64bit) + { + if(record_type == HANDSHAKE) + { + m_queue.insert(m_queue.end(), record.begin(), record.end()); + } + else if(record_type == CHANGE_CIPHER_SPEC) + { + if(record.size() != 1 || record[0] != 1) + throw Decoding_Error("Invalid ChangeCipherSpec"); + + // Pretend it's a regular handshake message of zero length + const byte ccs_hs[] = { HANDSHAKE_CCS, 0, 0, 0 }; + m_queue.insert(m_queue.end(), ccs_hs, ccs_hs + sizeof(ccs_hs)); + } + else + throw Decoding_Error("Unknown message type in handshake processing"); + } + +std::pair> +Stream_Handshake_IO::get_next_record(bool) + { + if(m_queue.size() >= 4) + { + const size_t length = load_be24(&m_queue[1]); + + if(m_queue.size() >= length + 4) + { + Handshake_Type type = static_cast(m_queue[0]); + + std::vector contents(m_queue.begin() + 4, + m_queue.begin() + 4 + length); + + m_queue.erase(m_queue.begin(), m_queue.begin() + 4 + length); + + return std::make_pair(type, contents); + } + } + + return std::make_pair(HANDSHAKE_NONE, std::vector()); + } + +std::vector +Stream_Handshake_IO::format(const std::vector& msg, + Handshake_Type type) const + { + std::vector send_buf(4 + msg.size()); + + const size_t buf_size = msg.size(); + + send_buf[0] = type; + + store_be24(&send_buf[1], buf_size); + + copy_mem(&send_buf[4], &msg[0], msg.size()); + + return send_buf; + } + +std::vector Stream_Handshake_IO::send(const Handshake_Message& msg) + { + const std::vector msg_bits = msg.serialize(); + + if(msg.type() == HANDSHAKE_CCS) + { + m_send_hs(CHANGE_CIPHER_SPEC, msg_bits); + return std::vector(); // not included in handshake hashes + } + + const std::vector buf = format(msg_bits, msg.type()); + m_send_hs(HANDSHAKE, buf); + return buf; + } + +Protocol_Version Datagram_Handshake_IO::initial_record_version() const + { + return Protocol_Version::DTLS_V10; + } + +void Datagram_Handshake_IO::add_record(const std::vector& record, + Record_Type record_type, + u64bit record_sequence) + { + const u16bit epoch = static_cast(record_sequence >> 48); + + if(record_type == CHANGE_CIPHER_SPEC) + { + m_ccs_epochs.insert(epoch); + return; + } + + const size_t DTLS_HANDSHAKE_HEADER_LEN = 12; + + const byte* record_bits = &record[0]; + size_t record_size = record.size(); + + while(record_size) + { + if(record_size < DTLS_HANDSHAKE_HEADER_LEN) + return; // completely bogus? at least degenerate/weird + + const byte msg_type = record_bits[0]; + const size_t msg_len = load_be24(&record_bits[1]); + const u16bit message_seq = load_be(&record_bits[4], 0); + const size_t fragment_offset = load_be24(&record_bits[6]); + const size_t fragment_length = load_be24(&record_bits[9]); + + const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length; + + if(record_size < total_size) + throw Decoding_Error("Bad lengths in DTLS header"); + + if(message_seq >= m_in_message_seq) + { + m_messages[message_seq].add_fragment(&record_bits[DTLS_HANDSHAKE_HEADER_LEN], + fragment_length, + fragment_offset, + epoch, + msg_type, + msg_len); + } + + record_bits += total_size; + record_size -= total_size; + } + } + +std::pair> +Datagram_Handshake_IO::get_next_record(bool expecting_ccs) + { + if(!m_flights.rbegin()->empty()) + m_flights.push_back(std::vector()); + + if(expecting_ccs) + { + if(!m_messages.empty()) + { + const u16bit current_epoch = m_messages.begin()->second.epoch(); + + if(m_ccs_epochs.count(current_epoch)) + return std::make_pair(HANDSHAKE_CCS, std::vector()); + } + + return std::make_pair(HANDSHAKE_NONE, std::vector()); + } + + auto i = m_messages.find(m_in_message_seq); + + if(i == m_messages.end() || !i->second.complete()) + return std::make_pair(HANDSHAKE_NONE, std::vector()); + + m_in_message_seq += 1; + + return i->second.message(); + } + +void Datagram_Handshake_IO::Handshake_Reassembly::add_fragment( + const byte fragment[], + size_t fragment_length, + size_t fragment_offset, + u16bit epoch, + byte msg_type, + size_t msg_length) + { + if(complete()) + return; // already have entire message, ignore this + + if(m_msg_type == HANDSHAKE_NONE) + { + m_epoch = epoch; + m_msg_type = msg_type; + m_msg_length = msg_length; + } + + if(msg_type != m_msg_type || msg_length != m_msg_length || epoch != m_epoch) + throw Decoding_Error("Inconsistent values in DTLS handshake header"); + + if(fragment_offset > m_msg_length) + throw Decoding_Error("Fragment offset past end of message"); + + if(fragment_offset + fragment_length > m_msg_length) + throw Decoding_Error("Fragment overlaps past end of message"); + + if(fragment_offset == 0 && fragment_length == m_msg_length) + { + m_fragments.clear(); + m_message.assign(fragment, fragment+fragment_length); + } + else + { + /* + * FIXME. This is a pretty lame way to do defragmentation, huge + * overhead with a tree node per byte. + * + * Also should confirm that all overlaps have no changes, + * otherwise we expose ourselves to the classic fingerprinting + * and IDS evasion attacks on IP fragmentation. + */ + for(size_t i = 0; i != fragment_length; ++i) + m_fragments[fragment_offset+i] = fragment[i]; + + if(m_fragments.size() == m_msg_length) + { + m_message.resize(m_msg_length); + for(size_t i = 0; i != m_msg_length; ++i) + m_message[i] = m_fragments[i]; + m_fragments.clear(); + } + } + } + +bool Datagram_Handshake_IO::Handshake_Reassembly::complete() const + { + return (m_msg_type != HANDSHAKE_NONE && m_message.size() == m_msg_length); + } + +std::pair> +Datagram_Handshake_IO::Handshake_Reassembly::message() const + { + if(!complete()) + throw Internal_Error("Datagram_Handshake_IO - message not complete"); + + return std::make_pair(static_cast(m_msg_type), m_message); + } + +std::vector +Datagram_Handshake_IO::format_fragment(const byte fragment[], + size_t frag_len, + u16bit frag_offset, + u16bit msg_len, + Handshake_Type type, + u16bit msg_sequence) const + { + std::vector send_buf(12 + frag_len); + + send_buf[0] = type; + + store_be24(&send_buf[1], msg_len); + + store_be(msg_sequence, &send_buf[4]); + + store_be24(&send_buf[6], frag_offset); + store_be24(&send_buf[9], frag_len); + + copy_mem(&send_buf[12], &fragment[0], frag_len); + + return send_buf; + } + +std::vector +Datagram_Handshake_IO::format_w_seq(const std::vector& msg, + Handshake_Type type, + u16bit msg_sequence) const + { + return format_fragment(&msg[0], msg.size(), 0, msg.size(), type, msg_sequence); + } + +std::vector +Datagram_Handshake_IO::format(const std::vector& msg, + Handshake_Type type) const + { + return format_w_seq(msg, type, m_in_message_seq - 1); + } + +namespace { + +size_t split_for_mtu(size_t mtu, size_t msg_size) + { + const size_t DTLS_HEADERS_SIZE = 25; // DTLS record+handshake headers + + const size_t parts = (msg_size + mtu) / mtu; + + if(parts + DTLS_HEADERS_SIZE > mtu) + return parts + 1; + + return parts; + } + +} + +std::vector +Datagram_Handshake_IO::send(const Handshake_Message& msg) + { + const std::vector msg_bits = msg.serialize(); + const u16bit epoch = m_seqs.current_write_epoch(); + const Handshake_Type msg_type = msg.type(); + + std::tuple> msg_info(epoch, msg_type, msg_bits); + + if(msg_type == HANDSHAKE_CCS) + { + m_send_hs(epoch, CHANGE_CIPHER_SPEC, msg_bits); + return std::vector(); // not included in handshake hashes + } + + const std::vector no_fragment = + format_w_seq(msg_bits, msg_type, m_out_message_seq); + + if(no_fragment.size() + DTLS_HEADER_SIZE <= m_mtu) + m_send_hs(epoch, HANDSHAKE, no_fragment); + else + { + const size_t parts = split_for_mtu(m_mtu, msg_bits.size()); + + const size_t parts_size = (msg_bits.size() + parts) / parts; + + size_t frag_offset = 0; + + while(frag_offset != msg_bits.size()) + { + const size_t frag_len = + std::min(msg_bits.size() - frag_offset, + parts_size); + + m_send_hs(epoch, + HANDSHAKE, + format_fragment(&msg_bits[frag_offset], + frag_len, + frag_offset, + msg_bits.size(), + msg_type, + m_out_message_seq)); + + frag_offset += frag_len; + } + } + + // Note: not saving CCS, instead we know it was there due to change in epoch + m_flights.rbegin()->push_back(m_out_message_seq); + m_flight_data[m_out_message_seq] = msg_info; + + m_out_message_seq += 1; + + return no_fragment; + } + +} + +} diff --git a/src/lib/tls/tls_handshake_io.h b/src/lib/tls/tls_handshake_io.h new file mode 100644 index 000000000..36c605c30 --- /dev/null +++ b/src/lib/tls/tls_handshake_io.h @@ -0,0 +1,168 @@ +/* +* TLS Handshake Serialization +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_IO_H__ +#define BOTAN_TLS_HANDSHAKE_IO_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Handshake_Message; + +/** +* Handshake IO Interface +*/ +class Handshake_IO + { + public: + virtual Protocol_Version initial_record_version() const = 0; + + virtual std::vector send(const Handshake_Message& msg) = 0; + + virtual std::vector format( + const std::vector& handshake_msg, + Handshake_Type handshake_type) const = 0; + + virtual void add_record(const std::vector& record, + Record_Type type, + u64bit sequence_number) = 0; + + /** + * Returns (HANDSHAKE_NONE, std::vector<>()) if no message currently available + */ + virtual std::pair> + get_next_record(bool expecting_ccs) = 0; + + Handshake_IO() {} + + Handshake_IO(const Handshake_IO&) = delete; + + Handshake_IO& operator=(const Handshake_IO&) = delete; + + virtual ~Handshake_IO() {} + }; + +/** +* Handshake IO for stream-based handshakes +*/ +class Stream_Handshake_IO : public Handshake_IO + { + public: + Stream_Handshake_IO(std::function&)> writer) : + m_send_hs(writer) {} + + Protocol_Version initial_record_version() const override; + + std::vector send(const Handshake_Message& msg) override; + + std::vector format( + const std::vector& handshake_msg, + Handshake_Type handshake_type) const override; + + void add_record(const std::vector& record, + Record_Type type, + u64bit sequence_number) override; + + std::pair> + get_next_record(bool expecting_ccs) override; + private: + std::deque m_queue; + std::function&)> m_send_hs; + }; + +/** +* Handshake IO for datagram-based handshakes +*/ +class Datagram_Handshake_IO : public Handshake_IO + { + public: + Datagram_Handshake_IO(class Connection_Sequence_Numbers& seq, + std::function&)> writer) : + m_seqs(seq), m_flights(1), m_send_hs(writer) {} + + Protocol_Version initial_record_version() const override; + + std::vector send(const Handshake_Message& msg) override; + + std::vector format( + const std::vector& handshake_msg, + Handshake_Type handshake_type) const override; + + void add_record(const std::vector& record, + Record_Type type, + u64bit sequence_number) override; + + std::pair> + get_next_record(bool expecting_ccs) override; + private: + std::vector format_fragment( + const byte fragment[], + size_t fragment_len, + u16bit frag_offset, + u16bit msg_len, + Handshake_Type type, + u16bit msg_sequence) const; + + std::vector format_w_seq( + const std::vector& handshake_msg, + Handshake_Type handshake_type, + u16bit msg_sequence) const; + + class Handshake_Reassembly + { + public: + void add_fragment(const byte fragment[], + size_t fragment_length, + size_t fragment_offset, + u16bit epoch, + byte msg_type, + size_t msg_length); + + bool complete() const; + + u16bit epoch() const { return m_epoch; } + + std::pair> message() const; + private: + byte m_msg_type = HANDSHAKE_NONE; + size_t m_msg_length = 0; + u16bit m_epoch = 0; + + std::map m_fragments; + std::vector m_message; + }; + + class Connection_Sequence_Numbers& m_seqs; + std::map m_messages; + std::set m_ccs_epochs; + std::vector> m_flights; + std::map>> m_flight_data; + + // default MTU is IPv6 min MTU minus UDP/IP headers + u16bit m_mtu = 1280 - 40 - 8; + u16bit m_in_message_seq = 0; + u16bit m_out_message_seq = 0; + std::function&)> m_send_hs; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_handshake_msg.h b/src/lib/tls/tls_handshake_msg.h new file mode 100644 index 000000000..1c44554d3 --- /dev/null +++ b/src/lib/tls/tls_handshake_msg.h @@ -0,0 +1,36 @@ +/* +* TLS Handshake Message +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_MSG_H__ +#define BOTAN_TLS_HANDSHAKE_MSG_H__ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Handshake Message Base Class +*/ +class BOTAN_DLL Handshake_Message + { + public: + virtual Handshake_Type type() const = 0; + + virtual std::vector serialize() const = 0; + + virtual ~Handshake_Message() {} + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp new file mode 100644 index 000000000..84b22cc09 --- /dev/null +++ b/src/lib/tls/tls_handshake_state.cpp @@ -0,0 +1,442 @@ +/* +* TLS Handshaking +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +u32bit bitmask_for_handshake_type(Handshake_Type type) + { + switch(type) + { + case HELLO_VERIFY_REQUEST: + return (1 << 0); + + case HELLO_REQUEST: + return (1 << 1); + + /* + * Same code point for both client hello styles + */ + case CLIENT_HELLO: + case CLIENT_HELLO_SSLV2: + return (1 << 2); + + case SERVER_HELLO: + return (1 << 3); + + case CERTIFICATE: + return (1 << 4); + + case CERTIFICATE_URL: + return (1 << 5); + + case CERTIFICATE_STATUS: + return (1 << 6); + + case SERVER_KEX: + return (1 << 7); + + case CERTIFICATE_REQUEST: + return (1 << 8); + + case SERVER_HELLO_DONE: + return (1 << 9); + + case CERTIFICATE_VERIFY: + return (1 << 10); + + case CLIENT_KEX: + return (1 << 11); + + case NEXT_PROTOCOL: + return (1 << 12); + + case NEW_SESSION_TICKET: + return (1 << 13); + + case HANDSHAKE_CCS: + return (1 << 14); + + case FINISHED: + return (1 << 15); + + // allow explicitly disabling new handshakes + case HANDSHAKE_NONE: + return 0; + } + + throw Internal_Error("Unknown handshake type " + std::to_string(type)); + } + +} + +/* +* Initialize the SSL/TLS Handshake State +*/ +Handshake_State::Handshake_State(Handshake_IO* io, + std::function msg_callback) : + m_msg_callback(msg_callback), + m_handshake_io(io), + m_version(m_handshake_io->initial_record_version()) + { + } + +Handshake_State::~Handshake_State() {} + +void Handshake_State::hello_verify_request(const Hello_Verify_Request& hello_verify) + { + note_message(hello_verify); + + m_client_hello->update_hello_cookie(hello_verify); + hash().reset(); + hash().update(handshake_io().send(*m_client_hello)); + note_message(*m_client_hello); + } + +void Handshake_State::client_hello(Client_Hello* client_hello) + { + m_client_hello.reset(client_hello); + note_message(*m_client_hello); + } + +void Handshake_State::server_hello(Server_Hello* server_hello) + { + m_server_hello.reset(server_hello); + m_ciphersuite = Ciphersuite::by_id(m_server_hello->ciphersuite()); + note_message(*m_server_hello); + } + +void Handshake_State::server_certs(Certificate* server_certs) + { + m_server_certs.reset(server_certs); + note_message(*m_server_certs); + } + +void Handshake_State::server_kex(Server_Key_Exchange* server_kex) + { + m_server_kex.reset(server_kex); + note_message(*m_server_kex); + } + +void Handshake_State::cert_req(Certificate_Req* cert_req) + { + m_cert_req.reset(cert_req); + note_message(*m_cert_req); + } + +void Handshake_State::server_hello_done(Server_Hello_Done* server_hello_done) + { + m_server_hello_done.reset(server_hello_done); + note_message(*m_server_hello_done); + } + +void Handshake_State::client_certs(Certificate* client_certs) + { + m_client_certs.reset(client_certs); + note_message(*m_client_certs); + } + +void Handshake_State::client_kex(Client_Key_Exchange* client_kex) + { + m_client_kex.reset(client_kex); + note_message(*m_client_kex); + } + +void Handshake_State::client_verify(Certificate_Verify* client_verify) + { + m_client_verify.reset(client_verify); + note_message(*m_client_verify); + } + +void Handshake_State::next_protocol(Next_Protocol* next_protocol) + { + m_next_protocol.reset(next_protocol); + note_message(*m_next_protocol); + } + +void Handshake_State::new_session_ticket(New_Session_Ticket* new_session_ticket) + { + m_new_session_ticket.reset(new_session_ticket); + note_message(*m_new_session_ticket); + } + +void Handshake_State::server_finished(Finished* server_finished) + { + m_server_finished.reset(server_finished); + note_message(*m_server_finished); + } + +void Handshake_State::client_finished(Finished* client_finished) + { + m_client_finished.reset(client_finished); + note_message(*m_client_finished); + } + +void Handshake_State::set_version(const Protocol_Version& version) + { + m_version = version; + } + +void Handshake_State::compute_session_keys() + { + m_session_keys = Session_Keys(this, client_kex()->pre_master_secret(), false); + } + +void Handshake_State::compute_session_keys(const secure_vector& resume_master_secret) + { + m_session_keys = Session_Keys(this, resume_master_secret, true); + } + +void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg) + { + const u32bit mask = bitmask_for_handshake_type(handshake_msg); + + m_hand_received_mask |= mask; + + const bool ok = (m_hand_expecting_mask & mask); // overlap? + + if(!ok) + throw Unexpected_Message("Unexpected state transition in handshake, got " + + std::to_string(handshake_msg) + + " expected " + std::to_string(m_hand_expecting_mask) + + " received " + std::to_string(m_hand_received_mask)); + + /* We don't know what to expect next, so force a call to + set_expected_next; if it doesn't happen, the next transition + check will always fail which is what we want. + */ + m_hand_expecting_mask = 0; + } + +void Handshake_State::set_expected_next(Handshake_Type handshake_msg) + { + m_hand_expecting_mask |= bitmask_for_handshake_type(handshake_msg); + } + +bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const + { + const u32bit mask = bitmask_for_handshake_type(handshake_msg); + + return (m_hand_received_mask & mask); + } + +std::pair> +Handshake_State::get_next_handshake_msg() + { + const bool expecting_ccs = + (bitmask_for_handshake_type(HANDSHAKE_CCS) & m_hand_expecting_mask); + + return m_handshake_io->get_next_record(expecting_ccs); + } + +std::string Handshake_State::srp_identifier() const + { + if(ciphersuite().valid() && ciphersuite().kex_algo() == "SRP_SHA") + return client_hello()->srp_identifier(); + + return ""; + } + +std::vector Handshake_State::session_ticket() const + { + if(new_session_ticket() && !new_session_ticket()->ticket().empty()) + return new_session_ticket()->ticket(); + + return client_hello()->session_ticket(); + } + +KDF* Handshake_State::protocol_specific_prf() const + { + if(version() == Protocol_Version::SSL_V3) + { + return get_kdf("SSL3-PRF"); + } + else if(version().supports_ciphersuite_specific_prf()) + { + const std::string prf_algo = ciphersuite().prf_algo(); + + if(prf_algo == "MD5" || prf_algo == "SHA-1") + return get_kdf("TLS-12-PRF(SHA-256)"); + + return get_kdf("TLS-12-PRF(" + prf_algo + ")"); + } + else + { + // TLS v1.0, v1.1 and DTLS v1.0 + return get_kdf("TLS-PRF"); + } + + throw Internal_Error("Unknown version code " + version().to_string()); + } + +namespace { + +std::string choose_hash(const std::string& sig_algo, + Protocol_Version negotiated_version, + const Policy& policy, + bool for_client_auth, + const Client_Hello* client_hello, + const Certificate_Req* cert_req) + { + if(!negotiated_version.supports_negotiable_signature_algorithms()) + { + if(for_client_auth && negotiated_version == Protocol_Version::SSL_V3) + return "Raw"; + + if(sig_algo == "RSA") + return "Parallel(MD5,SHA-160)"; + + if(sig_algo == "DSA") + return "SHA-1"; + + if(sig_algo == "ECDSA") + return "SHA-1"; + + throw Internal_Error("Unknown TLS signature algo " + sig_algo); + } + + const auto supported_algos = for_client_auth ? + cert_req->supported_algos() : + client_hello->supported_algos(); + + if(!supported_algos.empty()) + { + const auto hashes = policy.allowed_signature_hashes(); + + /* + * Choose our most preferred hash that the counterparty supports + * in pairing with the signature algorithm we want to use. + */ + for(auto hash : hashes) + { + for(auto algo : supported_algos) + { + if(algo.first == hash && algo.second == sig_algo) + return hash; + } + } + } + + // TLS v1.2 default hash if the counterparty sent nothing + return "SHA-1"; + } + +} + +std::pair +Handshake_State::choose_sig_format(const Private_Key& key, + std::string& hash_algo_out, + std::string& sig_algo_out, + bool for_client_auth, + const Policy& policy) const + { + const std::string sig_algo = key.algo_name(); + + const std::string hash_algo = + choose_hash(sig_algo, + this->version(), + policy, + for_client_auth, + client_hello(), + cert_req()); + + if(this->version().supports_negotiable_signature_algorithms()) + { + hash_algo_out = hash_algo; + sig_algo_out = sig_algo; + } + + if(sig_algo == "RSA") + { + const std::string padding = "EMSA3(" + hash_algo + ")"; + + return std::make_pair(padding, IEEE_1363); + } + else if(sig_algo == "DSA" || sig_algo == "ECDSA") + { + const std::string padding = "EMSA1(" + hash_algo + ")"; + + return std::make_pair(padding, DER_SEQUENCE); + } + + throw Invalid_Argument(sig_algo + " is invalid/unknown for TLS signatures"); + } + +std::pair +Handshake_State::understand_sig_format(const Public_Key& key, + std::string hash_algo, + std::string sig_algo, + bool for_client_auth) const + { + const std::string algo_name = key.algo_name(); + + /* + FIXME: This should check what was sent against the client hello + preferences, or the certificate request, to ensure it was allowed + by those restrictions. + + Or not? + */ + + if(this->version().supports_negotiable_signature_algorithms()) + { + if(hash_algo == "") + throw Decoding_Error("Counterparty did not send hash/sig IDS"); + + if(sig_algo != algo_name) + throw Decoding_Error("Counterparty sent inconsistent key and sig types"); + } + else + { + if(hash_algo != "" || sig_algo != "") + throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); + } + + if(algo_name == "RSA") + { + if(for_client_auth && this->version() == Protocol_Version::SSL_V3) + { + hash_algo = "Raw"; + } + else if(!this->version().supports_negotiable_signature_algorithms()) + { + hash_algo = "Parallel(MD5,SHA-160)"; + } + + const std::string padding = "EMSA3(" + hash_algo + ")"; + return std::make_pair(padding, IEEE_1363); + } + else if(algo_name == "DSA" || algo_name == "ECDSA") + { + if(algo_name == "DSA" && for_client_auth && this->version() == Protocol_Version::SSL_V3) + { + hash_algo = "Raw"; + } + else if(!this->version().supports_negotiable_signature_algorithms()) + { + hash_algo = "SHA-1"; + } + + const std::string padding = "EMSA1(" + hash_algo + ")"; + + return std::make_pair(padding, DER_SEQUENCE); + } + + throw Invalid_Argument(algo_name + " is invalid/unknown for TLS signatures"); + } + +} + +} diff --git a/src/lib/tls/tls_handshake_state.h b/src/lib/tls/tls_handshake_state.h new file mode 100644 index 000000000..9afcd0374 --- /dev/null +++ b/src/lib/tls/tls_handshake_state.h @@ -0,0 +1,210 @@ +/* +* TLS Handshake State +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_STATE_H__ +#define BOTAN_TLS_HANDSHAKE_STATE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class KDF; + +namespace TLS { + +class Policy; + +class Hello_Verify_Request; +class Client_Hello; +class Server_Hello; +class Certificate; +class Server_Key_Exchange; +class Certificate_Req; +class Server_Hello_Done; +class Certificate; +class Client_Key_Exchange; +class Certificate_Verify; +class Next_Protocol; +class New_Session_Ticket; +class Finished; + +/** +* SSL/TLS Handshake State +*/ +class Handshake_State + { + public: + Handshake_State(Handshake_IO* io, + std::function msg_callback = + std::function()); + + virtual ~Handshake_State(); + + Handshake_State(const Handshake_State&) = delete; + Handshake_State& operator=(const Handshake_State&) = delete; + + Handshake_IO& handshake_io() { return *m_handshake_io; } + + /** + * Return true iff we have received a particular message already + * @param msg_type the message type + */ + bool received_handshake_msg(Handshake_Type msg_type) const; + + /** + * Confirm that we were expecting this message type + * @param msg_type the message type + */ + void confirm_transition_to(Handshake_Type msg_type); + + /** + * Record that we are expecting a particular message type next + * @param msg_type the message type + */ + void set_expected_next(Handshake_Type msg_type); + + std::pair> + get_next_handshake_msg(); + + std::vector session_ticket() const; + + std::pair + understand_sig_format(const Public_Key& key, + std::string hash_algo, + std::string sig_algo, + bool for_client_auth) const; + + std::pair + choose_sig_format(const Private_Key& key, + std::string& hash_algo, + std::string& sig_algo, + bool for_client_auth, + const Policy& policy) const; + + std::string srp_identifier() const; + + KDF* protocol_specific_prf() const; + + Protocol_Version version() const { return m_version; } + + void set_version(const Protocol_Version& version); + + void hello_verify_request(const Hello_Verify_Request& hello_verify); + + void client_hello(Client_Hello* client_hello); + void server_hello(Server_Hello* server_hello); + void server_certs(Certificate* server_certs); + void server_kex(Server_Key_Exchange* server_kex); + void cert_req(Certificate_Req* cert_req); + void server_hello_done(Server_Hello_Done* server_hello_done); + void client_certs(Certificate* client_certs); + void client_kex(Client_Key_Exchange* client_kex); + void client_verify(Certificate_Verify* client_verify); + void next_protocol(Next_Protocol* next_protocol); + void new_session_ticket(New_Session_Ticket* new_session_ticket); + void server_finished(Finished* server_finished); + void client_finished(Finished* client_finished); + + const Client_Hello* client_hello() const + { return m_client_hello.get(); } + + const Server_Hello* server_hello() const + { return m_server_hello.get(); } + + const Certificate* server_certs() const + { return m_server_certs.get(); } + + const Server_Key_Exchange* server_kex() const + { return m_server_kex.get(); } + + const Certificate_Req* cert_req() const + { return m_cert_req.get(); } + + const Server_Hello_Done* server_hello_done() const + { return m_server_hello_done.get(); } + + const Certificate* client_certs() const + { return m_client_certs.get(); } + + const Client_Key_Exchange* client_kex() const + { return m_client_kex.get(); } + + const Certificate_Verify* client_verify() const + { return m_client_verify.get(); } + + const Next_Protocol* next_protocol() const + { return m_next_protocol.get(); } + + const New_Session_Ticket* new_session_ticket() const + { return m_new_session_ticket.get(); } + + const Finished* server_finished() const + { return m_server_finished.get(); } + + const Finished* client_finished() const + { return m_client_finished.get(); } + + const Ciphersuite& ciphersuite() const { return m_ciphersuite; } + + const Session_Keys& session_keys() const { return m_session_keys; } + + void compute_session_keys(); + + void compute_session_keys(const secure_vector& resume_master_secret); + + Handshake_Hash& hash() { return m_handshake_hash; } + + const Handshake_Hash& hash() const { return m_handshake_hash; } + + void note_message(const Handshake_Message& msg) + { + if(m_msg_callback) + m_msg_callback(msg); + } + + private: + + std::function m_msg_callback; + + std::unique_ptr m_handshake_io; + + u32bit m_hand_expecting_mask = 0; + u32bit m_hand_received_mask = 0; + Protocol_Version m_version; + Ciphersuite m_ciphersuite; + Session_Keys m_session_keys; + Handshake_Hash m_handshake_hash; + + std::unique_ptr m_client_hello; + std::unique_ptr m_server_hello; + std::unique_ptr m_server_certs; + std::unique_ptr m_server_kex; + std::unique_ptr m_cert_req; + std::unique_ptr m_server_hello_done; + std::unique_ptr m_client_certs; + std::unique_ptr m_client_kex; + std::unique_ptr m_client_verify; + std::unique_ptr m_next_protocol; + std::unique_ptr m_new_session_ticket; + std::unique_ptr m_server_finished; + std::unique_ptr m_client_finished; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_heartbeats.cpp b/src/lib/tls/tls_heartbeats.cpp new file mode 100644 index 000000000..8c129858e --- /dev/null +++ b/src/lib/tls/tls_heartbeats.cpp @@ -0,0 +1,78 @@ +/* +* TLS Heartbeats +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Heartbeat_Message::Heartbeat_Message(const std::vector& buf) + { + TLS_Data_Reader reader(buf); + + const byte type = reader.get_byte(); + + if(type != 1 && type != 2) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Unknown heartbeat message type"); + + m_type = static_cast(type); + + m_payload = reader.get_range(2, 0, 16*1024); + + // padding follows and is ignored + } + +Heartbeat_Message::Heartbeat_Message(Type type, + const byte payload[], + size_t payload_len) : + m_type(type), + m_payload(payload, payload + payload_len) + { + } + +std::vector Heartbeat_Message::contents() const + { + std::vector send_buf(3 + m_payload.size() + 16); + send_buf[0] = m_type; + send_buf[1] = get_byte(0, m_payload.size()); + send_buf[2] = get_byte(1, m_payload.size()); + copy_mem(&send_buf[3], &m_payload[0], m_payload.size()); + // leave padding as all zeros + + return send_buf; + } + +std::vector Heartbeat_Support_Indicator::serialize() const + { + std::vector heartbeat(1); + heartbeat[0] = (m_peer_allowed_to_send ? 1 : 2); + return heartbeat; + } + +Heartbeat_Support_Indicator::Heartbeat_Support_Indicator(TLS_Data_Reader& reader, + u16bit extension_size) + { + if(extension_size != 1) + throw Decoding_Error("Strange size for heartbeat extension"); + + const byte code = reader.get_byte(); + + if(code != 1 && code != 2) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Unknown heartbeat code " + std::to_string(code)); + + m_peer_allowed_to_send = (code == 1); + } + +} + +} diff --git a/src/lib/tls/tls_heartbeats.h b/src/lib/tls/tls_heartbeats.h new file mode 100644 index 000000000..00b197089 --- /dev/null +++ b/src/lib/tls/tls_heartbeats.h @@ -0,0 +1,43 @@ +/* +* TLS Heartbeats +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HEARTBEATS_H__ +#define BOTAN_TLS_HEARTBEATS_H__ + +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Heartbeat message +*/ +class Heartbeat_Message + { + public: + enum Type { REQUEST = 1, RESPONSE = 2 }; + + std::vector contents() const; + + const std::vector& payload() const { return m_payload; } + + bool is_request() const { return m_type == REQUEST; } + + Heartbeat_Message(const std::vector& buf); + + Heartbeat_Message(Type type, const byte payload[], size_t payload_len); + private: + Type m_type; + std::vector m_payload; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_magic.h b/src/lib/tls/tls_magic.h new file mode 100644 index 000000000..51f1fce47 --- /dev/null +++ b/src/lib/tls/tls_magic.h @@ -0,0 +1,72 @@ +/* +* SSL/TLS Protocol Constants +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H__ +#define BOTAN_TLS_PROTOCOL_MAGIC_H__ + +namespace Botan { + +namespace TLS { + +/** +* Protocol Constants for SSL/TLS +*/ +enum Size_Limits { + TLS_HEADER_SIZE = 5, + DTLS_HEADER_SIZE = TLS_HEADER_SIZE + 8, + + MAX_PLAINTEXT_SIZE = 16*1024, + MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024, + MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024, +}; + +enum Connection_Side { CLIENT = 1, SERVER = 2 }; + +enum Record_Type { + NO_RECORD = 0, + + CHANGE_CIPHER_SPEC = 20, + ALERT = 21, + HANDSHAKE = 22, + APPLICATION_DATA = 23, + HEARTBEAT = 24, +}; + +enum Handshake_Type { + HELLO_REQUEST = 0, + CLIENT_HELLO = 1, + CLIENT_HELLO_SSLV2 = 253, // Not a wire value + SERVER_HELLO = 2, + HELLO_VERIFY_REQUEST = 3, + NEW_SESSION_TICKET = 4, // RFC 5077 + CERTIFICATE = 11, + SERVER_KEX = 12, + CERTIFICATE_REQUEST = 13, + SERVER_HELLO_DONE = 14, + CERTIFICATE_VERIFY = 15, + CLIENT_KEX = 16, + FINISHED = 20, + + CERTIFICATE_URL = 21, + CERTIFICATE_STATUS = 22, + + NEXT_PROTOCOL = 67, + + HANDSHAKE_CCS = 254, // Not a wire value + HANDSHAKE_NONE = 255 // Null value +}; + +enum Compression_Method { + NO_COMPRESSION = 0x00, + DEFLATE_COMPRESSION = 0x01 +}; + +} + +} + +#endif diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h new file mode 100644 index 000000000..155d2427b --- /dev/null +++ b/src/lib/tls/tls_messages.h @@ -0,0 +1,567 @@ +/* +* TLS Messages +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_MESSAGES_H__ +#define BOTAN_TLS_MESSAGES_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class Credentials_Manager; +class SRP6_Server_Session; + +namespace TLS { + +class Handshake_IO; + +std::vector make_hello_random(RandomNumberGenerator& rng); + +/** +* DTLS Hello Verify Request +*/ +class Hello_Verify_Request : public Handshake_Message + { + public: + std::vector serialize() const override; + Handshake_Type type() const override { return HELLO_VERIFY_REQUEST; } + + std::vector cookie() const { return m_cookie; } + + Hello_Verify_Request(const std::vector& buf); + + Hello_Verify_Request(const std::vector& client_hello_bits, + const std::string& client_identity, + const SymmetricKey& secret_key); + private: + std::vector m_cookie; + }; + +/** +* Client Hello Message +*/ +class Client_Hello : public Handshake_Message + { + public: + Handshake_Type type() const override { return CLIENT_HELLO; } + + Protocol_Version version() const { return m_version; } + + const std::vector& random() const { return m_random; } + + const std::vector& session_id() const { return m_session_id; } + + std::vector ciphersuites() const { return m_suites; } + + std::vector compression_methods() const { return m_comp_methods; } + + bool offered_suite(u16bit ciphersuite) const; + + std::vector> supported_algos() const + { + if(Signature_Algorithms* sigs = m_extensions.get()) + return sigs->supported_signature_algorthms(); + return std::vector>(); + } + + std::vector supported_ecc_curves() const + { + if(Supported_Elliptic_Curves* ecc = m_extensions.get()) + return ecc->curves(); + return std::vector(); + } + + std::string sni_hostname() const + { + if(Server_Name_Indicator* sni = m_extensions.get()) + return sni->host_name(); + return ""; + } + + std::string srp_identifier() const + { + if(SRP_Identifier* srp = m_extensions.get()) + return srp->identifier(); + return ""; + } + + bool secure_renegotiation() const + { + return m_extensions.get(); + } + + std::vector renegotiation_info() const + { + if(Renegotiation_Extension* reneg = m_extensions.get()) + return reneg->renegotiation_info(); + return std::vector(); + } + + bool next_protocol_notification() const + { + return m_extensions.get(); + } + + size_t fragment_size() const + { + if(Maximum_Fragment_Length* frag = m_extensions.get()) + return frag->fragment_size(); + return 0; + } + + bool supports_session_ticket() const + { + return m_extensions.get(); + } + + std::vector session_ticket() const + { + if(Session_Ticket* ticket = m_extensions.get()) + return ticket->contents(); + return std::vector(); + } + + bool supports_heartbeats() const + { + return m_extensions.get(); + } + + bool peer_can_send_heartbeats() const + { + if(Heartbeat_Support_Indicator* hb = m_extensions.get()) + return hb->peer_allowed_to_send(); + return false; + } + + void update_hello_cookie(const Hello_Verify_Request& hello_verify); + + Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + Protocol_Version version, + const Policy& policy, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + bool next_protocol = false, + const std::string& hostname = "", + const std::string& srp_identifier = ""); + + Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Session& resumed_session, + bool next_protocol = false); + + Client_Hello(const std::vector& buf, + Handshake_Type type); + + private: + std::vector serialize() const override; + void deserialize(const std::vector& buf); + void deserialize_sslv2(const std::vector& buf); + + Protocol_Version m_version; + std::vector m_session_id; + std::vector m_random; + std::vector m_suites; + std::vector m_comp_methods; + std::vector m_hello_cookie; // DTLS only + + Extensions m_extensions; + }; + +/** +* Server Hello Message +*/ +class Server_Hello : public Handshake_Message + { + public: + Handshake_Type type() const override { return SERVER_HELLO; } + + Protocol_Version version() const { return m_version; } + + const std::vector& random() const { return m_random; } + + const std::vector& session_id() const { return m_session_id; } + + u16bit ciphersuite() const { return m_ciphersuite; } + + byte compression_method() const { return m_comp_method; } + + bool secure_renegotiation() const + { + return m_extensions.get(); + } + + std::vector renegotiation_info() const + { + if(Renegotiation_Extension* reneg = m_extensions.get()) + return reneg->renegotiation_info(); + return std::vector(); + } + + bool next_protocol_notification() const + { + return m_extensions.get(); + } + + std::vector next_protocols() const + { + if(Next_Protocol_Notification* npn = m_extensions.get()) + return npn->protocols(); + return std::vector(); + } + + size_t fragment_size() const + { + if(Maximum_Fragment_Length* frag = m_extensions.get()) + return frag->fragment_size(); + return 0; + } + + bool supports_session_ticket() const + { + return m_extensions.get(); + } + + bool supports_heartbeats() const + { + return m_extensions.get(); + } + + bool peer_can_send_heartbeats() const + { + if(Heartbeat_Support_Indicator* hb = m_extensions.get()) + return hb->peer_allowed_to_send(); + return false; + } + + Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + const std::vector& session_id, + Protocol_Version ver, + u16bit ciphersuite, + byte compression, + size_t max_fragment_size, + bool client_has_secure_renegotiation, + const std::vector& reneg_info, + bool offer_session_ticket, + bool client_has_npn, + const std::vector& next_protocols, + bool client_has_heartbeat, + RandomNumberGenerator& rng); + + Server_Hello(const std::vector& buf); + private: + std::vector serialize() const override; + + Protocol_Version m_version; + std::vector m_session_id, m_random; + u16bit m_ciphersuite; + byte m_comp_method; + + Extensions m_extensions; + }; + +/** +* Client Key Exchange Message +*/ +class Client_Key_Exchange : public Handshake_Message + { + public: + Handshake_Type type() const override { return CLIENT_KEX; } + + const secure_vector& pre_master_secret() const + { return m_pre_master; } + + Client_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + const Public_Key* server_public_key, + const std::string& hostname, + RandomNumberGenerator& rng); + + Client_Key_Exchange(const std::vector& buf, + const Handshake_State& state, + const Private_Key* server_rsa_kex_key, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng); + + private: + std::vector serialize() const override + { return m_key_material; } + + std::vector m_key_material; + secure_vector m_pre_master; + }; + +/** +* Certificate Message +*/ +class Certificate : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE; } + const std::vector& cert_chain() const { return m_certs; } + + size_t count() const { return m_certs.size(); } + bool empty() const { return m_certs.empty(); } + + Certificate(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& certs); + + Certificate(const std::vector& buf); + private: + std::vector serialize() const override; + + std::vector m_certs; + }; + +/** +* Certificate Request Message +*/ +class Certificate_Req : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE_REQUEST; } + + const std::vector& acceptable_cert_types() const + { return m_cert_key_types; } + + std::vector acceptable_CAs() const { return m_names; } + + std::vector > supported_algos() const + { return m_supported_algos; } + + Certificate_Req(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + const std::vector& allowed_cas, + Protocol_Version version); + + Certificate_Req(const std::vector& buf, + Protocol_Version version); + private: + std::vector serialize() const override; + + std::vector m_names; + std::vector m_cert_key_types; + + std::vector > m_supported_algos; + }; + +/** +* Certificate Verify Message +*/ +class Certificate_Verify : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE_VERIFY; } + + /** + * Check the signature on a certificate verify message + * @param cert the purported certificate + * @param state the handshake state + */ + bool verify(const X509_Certificate& cert, + const Handshake_State& state) const; + + Certificate_Verify(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + RandomNumberGenerator& rng, + const Private_Key* key); + + Certificate_Verify(const std::vector& buf, + Protocol_Version version); + private: + std::vector serialize() const override; + + std::string m_sig_algo; // sig algo used to create signature + std::string m_hash_algo; // hash used to create signature + std::vector m_signature; + }; + +/** +* Finished Message +*/ +class Finished : public Handshake_Message + { + public: + Handshake_Type type() const override { return FINISHED; } + + std::vector verify_data() const + { return m_verification_data; } + + bool verify(const Handshake_State& state, + Connection_Side side) const; + + Finished(Handshake_IO& io, + Handshake_State& state, + Connection_Side side); + + Finished(const std::vector& buf); + private: + std::vector serialize() const override; + + std::vector m_verification_data; + }; + +/** +* Hello Request Message +*/ +class Hello_Request : public Handshake_Message + { + public: + Handshake_Type type() const override { return HELLO_REQUEST; } + + Hello_Request(Handshake_IO& io); + Hello_Request(const std::vector& buf); + private: + std::vector serialize() const override; + }; + +/** +* Server Key Exchange Message +*/ +class Server_Key_Exchange : public Handshake_Message + { + public: + Handshake_Type type() const override { return SERVER_KEX; } + + const std::vector& params() const { return m_params; } + + bool verify(const Public_Key& server_key, + const Handshake_State& state) const; + + // Only valid for certain kex types + const Private_Key& server_kex_key() const; + + // Only valid for SRP negotiation + SRP6_Server_Session& server_srp_params() const; + + Server_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + RandomNumberGenerator& rng, + const Private_Key* signing_key = nullptr); + + Server_Key_Exchange(const std::vector& buf, + const std::string& kex_alg, + const std::string& sig_alg, + Protocol_Version version); + + ~Server_Key_Exchange(); + private: + std::vector serialize() const override; + + std::unique_ptr m_kex_key; + std::unique_ptr m_srp_params; + + std::vector m_params; + + std::string m_sig_algo; // sig algo used to create signature + std::string m_hash_algo; // hash used to create signature + std::vector m_signature; + }; + +/** +* Server Hello Done Message +*/ +class Server_Hello_Done : public Handshake_Message + { + public: + Handshake_Type type() const override { return SERVER_HELLO_DONE; } + + Server_Hello_Done(Handshake_IO& io, Handshake_Hash& hash); + Server_Hello_Done(const std::vector& buf); + private: + std::vector serialize() const override; + }; + +/** +* Next Protocol Message +*/ +class Next_Protocol : public Handshake_Message + { + public: + Handshake_Type type() const override { return NEXT_PROTOCOL; } + + std::string protocol() const { return m_protocol; } + + Next_Protocol(Handshake_IO& io, + Handshake_Hash& hash, + const std::string& protocol); + + Next_Protocol(const std::vector& buf); + private: + std::vector serialize() const override; + + std::string m_protocol; + }; + +/** +* New Session Ticket Message +*/ +class New_Session_Ticket : public Handshake_Message + { + public: + Handshake_Type type() const override { return NEW_SESSION_TICKET; } + + u32bit ticket_lifetime_hint() const { return m_ticket_lifetime_hint; } + const std::vector& ticket() const { return m_ticket; } + + New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& ticket, + u32bit lifetime); + + New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash); + + New_Session_Ticket(const std::vector& buf); + private: + std::vector serialize() const override; + + u32bit m_ticket_lifetime_hint; + std::vector m_ticket; + }; + +/** +* Change Cipher Spec +*/ +class Change_Cipher_Spec : public Handshake_Message + { + public: + Handshake_Type type() const override { return HANDSHAKE_CCS; } + + std::vector serialize() const override + { return std::vector(1, 1); } + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp new file mode 100644 index 000000000..05251e186 --- /dev/null +++ b/src/lib/tls/tls_policy.cpp @@ -0,0 +1,286 @@ +/* +* Policies for TLS +* (C) 2004-2010,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +std::vector Policy::allowed_ciphers() const + { + return std::vector({ + "AES-256/GCM", + "AES-128/GCM", + "AES-256/CCM", + "AES-128/CCM", + "AES-256/CCM-8", + "AES-128/CCM-8", + //"Camellia-256/GCM", + //"Camellia-128/GCM", + "AES-256", + "AES-128", + //"Camellia-256", + //"Camellia-128", + //"SEED" + //"3DES", + //"RC4", + }); + } + +std::vector Policy::allowed_signature_hashes() const + { + return std::vector({ + "SHA-512", + "SHA-384", + "SHA-256", + "SHA-224", + //"SHA-1", + //"MD5", + }); + } + +std::vector Policy::allowed_macs() const + { + return std::vector({ + "AEAD", + "SHA-384", + "SHA-256", + "SHA-1", + //"MD5", + }); + } + +std::vector Policy::allowed_key_exchange_methods() const + { + return std::vector({ + "SRP_SHA", + //"ECDHE_PSK", + //"DHE_PSK", + //"PSK", + "ECDH", + "DH", + "RSA", + }); + } + +std::vector Policy::allowed_signature_methods() const + { + return std::vector({ + "ECDSA", + "RSA", + "DSA", + //"" + }); + } + +std::vector Policy::allowed_ecc_curves() const + { + return std::vector({ + "brainpool512r1", + "brainpool384r1", + "brainpool256r1", + "secp521r1", + "secp384r1", + "secp256r1", + "secp256k1", + "secp224r1", + "secp224k1", + //"secp192r1", + //"secp192k1", + //"secp160r2", + //"secp160r1", + //"secp160k1", + }); + } + +/* +* Choose an ECC curve to use +*/ +std::string Policy::choose_curve(const std::vector& curve_names) const + { + const std::vector our_curves = allowed_ecc_curves(); + + for(size_t i = 0; i != our_curves.size(); ++i) + if(value_exists(curve_names, our_curves[i])) + return our_curves[i]; + + return ""; // no shared curve + } + +DL_Group Policy::dh_group() const + { + return DL_Group("modp/ietf/2048"); + } + +size_t Policy::minimum_dh_group_size() const + { + return 1024; + } + +/* +* Return allowed compression algorithms +*/ +std::vector Policy::compression() const + { + return std::vector{ NO_COMPRESSION }; + } + +u32bit Policy::session_ticket_lifetime() const + { + return 86400; // 1 day + } + +bool Policy::acceptable_protocol_version(Protocol_Version version) const + { + // By default require TLS to minimize surprise + if(version.is_datagram_protocol()) + return false; + + return (version > Protocol_Version::SSL_V3); + } + +bool Policy::acceptable_ciphersuite(const Ciphersuite&) const + { + return true; + } + +namespace { + +class Ciphersuite_Preference_Ordering + { + public: + Ciphersuite_Preference_Ordering(const std::vector& ciphers, + const std::vector& macs, + const std::vector& kex, + const std::vector& sigs) : + m_ciphers(ciphers), m_macs(macs), m_kex(kex), m_sigs(sigs) {} + + bool operator()(const Ciphersuite& a, const Ciphersuite& b) const + { + if(a.kex_algo() != b.kex_algo()) + { + for(size_t i = 0; i != m_kex.size(); ++i) + { + if(a.kex_algo() == m_kex[i]) + return true; + if(b.kex_algo() == m_kex[i]) + return false; + } + } + + if(a.cipher_algo() != b.cipher_algo()) + { + for(size_t i = 0; i != m_ciphers.size(); ++i) + { + if(a.cipher_algo() == m_ciphers[i]) + return true; + if(b.cipher_algo() == m_ciphers[i]) + return false; + } + } + + if(a.cipher_keylen() != b.cipher_keylen()) + { + if(a.cipher_keylen() < b.cipher_keylen()) + return false; + if(a.cipher_keylen() > b.cipher_keylen()) + return true; + } + + if(a.sig_algo() != b.sig_algo()) + { + for(size_t i = 0; i != m_sigs.size(); ++i) + { + if(a.sig_algo() == m_sigs[i]) + return true; + if(b.sig_algo() == m_sigs[i]) + return false; + } + } + + if(a.mac_algo() != b.mac_algo()) + { + for(size_t i = 0; i != m_macs.size(); ++i) + { + if(a.mac_algo() == m_macs[i]) + return true; + if(b.mac_algo() == m_macs[i]) + return false; + } + } + + return false; // equal (?!?) + } + private: + std::vector m_ciphers, m_macs, m_kex, m_sigs; + }; + +} + +std::vector Policy::ciphersuite_list(Protocol_Version version, + bool have_srp) const + { + const std::vector ciphers = allowed_ciphers(); + const std::vector macs = allowed_macs(); + const std::vector kex = allowed_key_exchange_methods(); + const std::vector sigs = allowed_signature_methods(); + + Ciphersuite_Preference_Ordering order(ciphers, macs, kex, sigs); + + std::set ciphersuites(order); + + for(auto suite : Ciphersuite::all_known_ciphersuites()) + { + if(!acceptable_ciphersuite(suite)) + continue; + + if(!have_srp && suite.kex_algo() == "SRP_SHA") + continue; + + if(version.is_datagram_protocol() && suite.cipher_algo() == "RC4") + continue; + + if(!version.supports_aead_modes() && suite.mac_algo() == "AEAD") + continue; + + if(!value_exists(kex, suite.kex_algo())) + continue; // unsupported key exchange + + if(!value_exists(ciphers, suite.cipher_algo())) + continue; // unsupported cipher + + if(!value_exists(macs, suite.mac_algo())) + continue; // unsupported MAC algo + + if(!value_exists(sigs, suite.sig_algo())) + { + // allow if it's an empty sig algo and we want to use PSK + if(suite.sig_algo() != "" || !suite.psk_ciphersuite()) + continue; + } + + // OK, allow it: + ciphersuites.insert(suite); + } + + if(ciphersuites.empty()) + throw std::logic_error("Policy does not allow any available cipher suite"); + + std::vector ciphersuite_codes; + for(auto i : ciphersuites) + ciphersuite_codes.push_back(i.ciphersuite_code()); + return ciphersuite_codes; + } + +} + +} diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h new file mode 100644 index 000000000..5b205dfeb --- /dev/null +++ b/src/lib/tls/tls_policy.h @@ -0,0 +1,194 @@ +/* +* Hooks for application level policies on TLS connections +* (C) 2004-2006,2013 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_POLICY_H__ +#define BOTAN_TLS_POLICY_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Policy Base Class +* Inherit and overload as desired to suit local policy concerns +*/ +class BOTAN_DLL Policy + { + public: + + /** + * Returns a list of ciphers we are willing to negotiate, in + * order of preference. + */ + virtual std::vector allowed_ciphers() const; + + /** + * Returns a list of hash algorithms we are willing to use for + * signatures, in order of preference. + */ + virtual std::vector allowed_signature_hashes() const; + + /** + * Returns a list of MAC algorithms we are willing to use. + */ + virtual std::vector allowed_macs() const; + + /** + * Returns a list of key exchange algorithms we are willing to + * use, in order of preference. Allowed values: DH, empty string + * (representing RSA using server certificate key) + */ + virtual std::vector allowed_key_exchange_methods() const; + + /** + * Returns a list of signature algorithms we are willing to + * use, in order of preference. Allowed values RSA and DSA. + */ + virtual std::vector allowed_signature_methods() const; + + /** + * Return list of ECC curves we are willing to use in order of preference + */ + virtual std::vector allowed_ecc_curves() const; + + /** + * Returns a list of compression algorithms we are willing to use, + * in order of preference. Allowed values any value of + * Compression_Method. + * + * @note Compression is not currently supported + */ + virtual std::vector compression() const; + + /** + * Choose an elliptic curve to use + */ + virtual std::string choose_curve(const std::vector& curve_names) const; + + /** + * Attempt to negotiate the use of the heartbeat extension + */ + virtual bool negotiate_heartbeat_support() const { return false; } + + /** + * Allow renegotiation even if the counterparty doesn't + * support the secure renegotiation extension. + * + * @warning Changing this to true exposes you to injected + * plaintext attacks. Read RFC 5746 for background. + */ + virtual bool allow_insecure_renegotiation() const { return false; } + + /** + * Allow servers to initiate a new handshake + */ + virtual bool allow_server_initiated_renegotiation() const { return true; } + + /** + * Return the group to use for ephemeral Diffie-Hellman key agreement + */ + virtual DL_Group dh_group() const; + + /** + * Return the minimum DH group size we're willing to use + */ + virtual size_t minimum_dh_group_size() const; + + /** + * If this function returns false, unknown SRP/PSK identifiers + * will be rejected with an unknown_psk_identifier alert as soon + * as the non-existence is identified. Otherwise, a false + * identifier value will be used and the protocol allowed to + * proceed, causing the handshake to eventually fail without + * revealing that the username does not exist on this system. + */ + virtual bool hide_unknown_users() const { return false; } + + /** + * Return the allowed lifetime of a session ticket. If 0, session + * tickets do not expire until the session ticket key rolls over. + * Expired session tickets cannot be used to resume a session. + */ + virtual u32bit session_ticket_lifetime() const; + + /** + * @return true if and only if we are willing to accept this version + * Default accepts only TLS, so override if you want to enable DTLS + * in your application. + */ + virtual bool acceptable_protocol_version(Protocol_Version version) const; + + virtual bool acceptable_ciphersuite(const Ciphersuite& suite) const; + + /** + * @return true if servers should choose the ciphersuite matching + * their highest preference, rather than the clients. + * Has no effect on client side. + */ + virtual bool server_uses_own_ciphersuite_preferences() const { return true; } + + /** + * Return allowed ciphersuites, in order of preference + */ + virtual std::vector ciphersuite_list(Protocol_Version version, + bool have_srp) const; + + virtual ~Policy() {} + }; + +/** +* NSA Suite B 128-bit security level (see @rfc 6460) +*/ +class BOTAN_DLL NSA_Suite_B_128 : public Policy + { + public: + std::vector allowed_ciphers() const override + { return std::vector({"AES-128/GCM"}); } + + std::vector allowed_signature_hashes() const override + { return std::vector({"SHA-256"}); } + + std::vector allowed_macs() const override + { return std::vector({"AEAD"}); } + + std::vector allowed_key_exchange_methods() const override + { return std::vector({"ECDH"}); } + + std::vector allowed_signature_methods() const override + { return std::vector({"ECDSA"}); } + + std::vector allowed_ecc_curves() const override + { return std::vector({"secp256r1"}); } + + bool acceptable_protocol_version(Protocol_Version version) const override + { return version == Protocol_Version::TLS_V12; } + }; + +/** +* Policy for DTLS. We require DTLS v1.2 and an AEAD mode +*/ +class BOTAN_DLL Datagram_Policy : public Policy + { + public: + std::vector allowed_macs() const override + { return std::vector({"AEAD"}); } + + bool acceptable_protocol_version(Protocol_Version version) const override + { return version == Protocol_Version::DTLS_V12; } + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_reader.h b/src/lib/tls/tls_reader.h new file mode 100644 index 000000000..7440e16b7 --- /dev/null +++ b/src/lib/tls/tls_reader.h @@ -0,0 +1,226 @@ +/* +* TLS Data Reader +* (C) 2010-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_READER_H__ +#define BOTAN_TLS_READER_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Helper class for decoding TLS protocol messages +*/ +class TLS_Data_Reader + { + public: + TLS_Data_Reader(const std::vector& buf_in) : + buf(buf_in), offset(0) {} + + void assert_done() const + { + if(has_remaining()) + throw Decoding_Error("Extra bytes at end of message"); + } + + size_t remaining_bytes() const + { + return buf.size() - offset; + } + + bool has_remaining() const + { + return (remaining_bytes() > 0); + } + + void discard_next(size_t bytes) + { + assert_at_least(bytes); + offset += bytes; + } + + u16bit get_u32bit() + { + assert_at_least(4); + u16bit result = make_u32bit(buf[offset ], buf[offset+1], + buf[offset+2], buf[offset+3]); + offset += 4; + return result; + } + + u16bit get_u16bit() + { + assert_at_least(2); + u16bit result = make_u16bit(buf[offset], buf[offset+1]); + offset += 2; + return result; + } + + byte get_byte() + { + assert_at_least(1); + byte result = buf[offset]; + offset += 1; + return result; + } + + template + Container get_elem(size_t num_elems) + { + assert_at_least(num_elems * sizeof(T)); + + Container result(num_elems); + + for(size_t i = 0; i != num_elems; ++i) + result[i] = load_be(&buf[offset], i); + + offset += num_elems * sizeof(T); + + return result; + } + + template + std::vector get_range(size_t len_bytes, + size_t min_elems, + size_t max_elems) + { + const size_t num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem >(num_elems); + } + + template + std::vector get_range_vector(size_t len_bytes, + size_t min_elems, + size_t max_elems) + { + const size_t num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem >(num_elems); + } + + std::string get_string(size_t len_bytes, + size_t min_bytes, + size_t max_bytes) + { + std::vector v = + get_range_vector(len_bytes, min_bytes, max_bytes); + + return std::string(reinterpret_cast(&v[0]), v.size()); + } + + template + std::vector get_fixed(size_t size) + { + return get_elem >(size); + } + + private: + size_t get_length_field(size_t len_bytes) + { + assert_at_least(len_bytes); + + if(len_bytes == 1) + return get_byte(); + else if(len_bytes == 2) + return get_u16bit(); + + throw Decoding_Error("TLS_Data_Reader: Bad length size"); + } + + size_t get_num_elems(size_t len_bytes, + size_t T_size, + size_t min_elems, + size_t max_elems) + { + const size_t byte_length = get_length_field(len_bytes); + + if(byte_length % T_size != 0) + throw Decoding_Error("TLS_Data_Reader: Size isn't multiple of T"); + + const size_t num_elems = byte_length / T_size; + + if(num_elems < min_elems || num_elems > max_elems) + throw Decoding_Error("TLS_Data_Reader: Range outside paramaters"); + + return num_elems; + } + + void assert_at_least(size_t n) const + { + if(buf.size() - offset < n) + { + throw Decoding_Error("TLS_Data_Reader: Expected " + std::to_string(n) + + " bytes remaining, only " + std::to_string(buf.size()-offset) + + " left"); + } + } + + const std::vector& buf; + size_t offset; + }; + +/** +* Helper function for encoding length-tagged vectors +*/ +template +void append_tls_length_value(std::vector& buf, + const T* vals, + size_t vals_size, + size_t tag_size) + { + const size_t T_size = sizeof(T); + const size_t val_bytes = T_size * vals_size; + + if(tag_size != 1 && tag_size != 2) + throw std::invalid_argument("append_tls_length_value: invalid tag size"); + + if((tag_size == 1 && val_bytes > 255) || + (tag_size == 2 && val_bytes > 65535)) + throw std::invalid_argument("append_tls_length_value: value too large"); + + for(size_t i = 0; i != tag_size; ++i) + buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); + + for(size_t i = 0; i != vals_size; ++i) + for(size_t j = 0; j != T_size; ++j) + buf.push_back(get_byte(j, vals[i])); + } + +template +void append_tls_length_value(std::vector& buf, + const std::vector& vals, + size_t tag_size) + { + append_tls_length_value(buf, &vals[0], vals.size(), tag_size); + } + +template +void append_tls_length_value(std::vector& buf, + const std::string& str, + size_t tag_size) + { + append_tls_length_value(buf, + reinterpret_cast(&str[0]), + str.size(), + tag_size); + } + +} + +} + +#endif diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp new file mode 100644 index 000000000..fc4908dc5 --- /dev/null +++ b/src/lib/tls/tls_record.cpp @@ -0,0 +1,622 @@ +/* +* TLS Record Handling +* (C) 2012,2013 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, + Connection_Side side, + bool our_side, + const Ciphersuite& suite, + const Session_Keys& keys) : + m_start_time(std::chrono::system_clock::now()), + m_is_ssl3(version == Protocol_Version::SSL_V3) + { + SymmetricKey mac_key, cipher_key; + InitializationVector iv; + + if(side == CLIENT) + { + cipher_key = keys.client_cipher_key(); + iv = keys.client_iv(); + mac_key = keys.client_mac_key(); + } + else + { + cipher_key = keys.server_cipher_key(); + iv = keys.server_iv(); + mac_key = keys.server_mac_key(); + } + + const std::string cipher_algo = suite.cipher_algo(); + const std::string mac_algo = suite.mac_algo(); + + if(AEAD_Mode* aead = get_aead(cipher_algo, our_side ? ENCRYPTION : DECRYPTION)) + { + m_aead.reset(aead); + m_aead->set_key(cipher_key + mac_key); + + BOTAN_ASSERT(iv.length() == 4, "Using 4/8 partial implicit nonce"); + m_nonce = iv.bits_of(); + m_nonce.resize(12); + return; + } + + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(cipher_algo)) + { + m_block_cipher.reset(bc->clone()); + m_block_cipher->set_key(cipher_key); + m_block_cipher_cbc_state = iv.bits_of(); + m_block_size = bc->block_size(); + + if(version.supports_explicit_cbc_ivs()) + m_iv_size = m_block_size; + } + else if(const StreamCipher* sc = af.prototype_stream_cipher(cipher_algo)) + { + m_stream_cipher.reset(sc->clone()); + m_stream_cipher->set_key(cipher_key); + } + else + throw Invalid_Argument("Unknown TLS cipher " + cipher_algo); + + if(version == Protocol_Version::SSL_V3) + m_mac.reset(af.make_mac("SSL3-MAC(" + mac_algo + ")")); + else + m_mac.reset(af.make_mac("HMAC(" + mac_algo + ")")); + + m_mac->set_key(mac_key); + } + +const secure_vector& Connection_Cipher_State::aead_nonce(u64bit seq) + { + BOTAN_ASSERT(m_aead, "Using AEAD mode"); + BOTAN_ASSERT(m_nonce.size() == 12, "Expected nonce size"); + store_be(seq, &m_nonce[4]); + return m_nonce; + } + +const secure_vector& +Connection_Cipher_State::aead_nonce(const byte record[], size_t record_len) + { + BOTAN_ASSERT(m_aead, "Using AEAD mode"); + BOTAN_ASSERT(m_nonce.size() == 12, "Expected nonce size"); + BOTAN_ASSERT(record_len >= 8, "Record includes nonce"); + copy_mem(&m_nonce[4], record, 8); + return m_nonce; + } + +const secure_vector& +Connection_Cipher_State::format_ad(u64bit msg_sequence, + byte msg_type, + Protocol_Version version, + u16bit msg_length) + { + m_ad.clear(); + for(size_t i = 0; i != 8; ++i) + m_ad.push_back(get_byte(i, msg_sequence)); + m_ad.push_back(msg_type); + + if(version != Protocol_Version::SSL_V3) + { + m_ad.push_back(version.major_version()); + m_ad.push_back(version.minor_version()); + } + + m_ad.push_back(get_byte(0, msg_length)); + m_ad.push_back(get_byte(1, msg_length)); + + return m_ad; + } + +void write_record(secure_vector& output, + byte msg_type, const byte msg[], size_t msg_length, + Protocol_Version version, + u64bit msg_sequence, + Connection_Cipher_State* cipherstate, + RandomNumberGenerator& rng) + { + output.clear(); + + output.push_back(msg_type); + output.push_back(version.major_version()); + output.push_back(version.minor_version()); + + if(version.is_datagram_protocol()) + { + for(size_t i = 0; i != 8; ++i) + output.push_back(get_byte(i, msg_sequence)); + } + + if(!cipherstate) // initial unencrypted handshake records + { + output.push_back(get_byte(0, msg_length)); + output.push_back(get_byte(1, msg_length)); + + output.insert(output.end(), &msg[0], &msg[msg_length]); + + return; + } + + if(AEAD_Mode* aead = cipherstate->aead()) + { + const size_t ctext_size = aead->output_length(msg_length); + + auto nonce = cipherstate->aead_nonce(msg_sequence); + const size_t implicit_nonce_bytes = 4; // FIXME, take from ciphersuite + const size_t explicit_nonce_bytes = 8; + + BOTAN_ASSERT(nonce.size() == implicit_nonce_bytes + explicit_nonce_bytes, + "Expected nonce size"); + + // wrong if start_vec returns something + const size_t rec_size = ctext_size + explicit_nonce_bytes; + + BOTAN_ASSERT(rec_size <= 0xFFFF, "Ciphertext length fits in field"); + + output.push_back(get_byte(0, rec_size)); + output.push_back(get_byte(1, rec_size)); + + aead->set_associated_data_vec( + cipherstate->format_ad(msg_sequence, msg_type, version, msg_length) + ); + + output += std::make_pair(&nonce[implicit_nonce_bytes], explicit_nonce_bytes); + output += aead->start_vec(nonce); + + const size_t offset = output.size(); + output += std::make_pair(&msg[0], msg_length); + aead->finish(output, offset); + + BOTAN_ASSERT(output.size() == offset + ctext_size, "Expected size"); + + BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE, + "Produced ciphertext larger than protocol allows"); + return; + } + + cipherstate->mac()->update( + cipherstate->format_ad(msg_sequence, msg_type, version, msg_length) + ); + + cipherstate->mac()->update(msg, msg_length); + + const size_t block_size = cipherstate->block_size(); + const size_t iv_size = cipherstate->iv_size(); + const size_t mac_size = cipherstate->mac_size(); + + const size_t buf_size = round_up( + iv_size + msg_length + mac_size + (block_size ? 1 : 0), + block_size); + + if(buf_size > MAX_CIPHERTEXT_SIZE) + throw Internal_Error("Output record is larger than allowed by protocol"); + + output.push_back(get_byte(0, buf_size)); + output.push_back(get_byte(1, buf_size)); + + const size_t header_size = output.size(); + + if(iv_size) + { + output.resize(output.size() + iv_size); + rng.randomize(&output[output.size() - iv_size], iv_size); + } + + output.insert(output.end(), &msg[0], &msg[msg_length]); + + output.resize(output.size() + mac_size); + cipherstate->mac()->final(&output[output.size() - mac_size]); + + if(block_size) + { + const size_t pad_val = + buf_size - (iv_size + msg_length + mac_size + 1); + + for(size_t i = 0; i != pad_val + 1; ++i) + output.push_back(pad_val); + } + + if(buf_size > MAX_CIPHERTEXT_SIZE) + throw Internal_Error("Produced ciphertext larger than protocol allows"); + + BOTAN_ASSERT(buf_size + header_size == output.size(), + "Output buffer is sized properly"); + + if(StreamCipher* sc = cipherstate->stream_cipher()) + { + sc->cipher1(&output[header_size], buf_size); + } + else if(BlockCipher* bc = cipherstate->block_cipher()) + { + secure_vector& cbc_state = cipherstate->cbc_state(); + + BOTAN_ASSERT(buf_size % block_size == 0, + "Buffer is an even multiple of block size"); + + byte* buf = &output[header_size]; + + const size_t blocks = buf_size / block_size; + + xor_buf(&buf[0], &cbc_state[0], block_size); + bc->encrypt(&buf[0]); + + for(size_t i = 1; i < blocks; ++i) + { + xor_buf(&buf[block_size*i], &buf[block_size*(i-1)], block_size); + bc->encrypt(&buf[block_size*i]); + } + + cbc_state.assign(&buf[block_size*(blocks-1)], + &buf[block_size*blocks]); + } + else + throw Internal_Error("NULL cipher not supported"); + } + +namespace { + +size_t fill_buffer_to(secure_vector& readbuf, + const byte*& input, + size_t& input_size, + size_t& input_consumed, + size_t desired) + { + if(readbuf.size() >= desired) + return 0; // already have it + + const size_t taken = std::min(input_size, desired - readbuf.size()); + + readbuf.insert(readbuf.end(), &input[0], &input[taken]); + input_consumed += taken; + input_size -= taken; + input += taken; + + return (desired - readbuf.size()); // how many bytes do we still need? + } + +/* +* Checks the TLS padding. Returns 0 if the padding is invalid (we +* count the padding_length field as part of the padding size so a +* valid padding will always be at least one byte long), or the length +* of the padding otherwise. This is actually padding_length + 1 +* because both the padding and padding_length fields are padding from +* our perspective. +* +* Returning 0 in the error case should ensure the MAC check will fail. +* This approach is suggested in section 6.2.3.2 of RFC 5246. +* +* Also returns 0 if block_size == 0, so can be safely called with a +* stream cipher in use. +* +* @fixme This should run in constant time +*/ +size_t tls_padding_check(bool sslv3_padding, + size_t block_size, + const byte record[], + size_t record_len) + { + const size_t padding_length = record[(record_len-1)]; + + if(padding_length >= record_len) + return 0; + + /* + * SSL v3 requires that the padding be less than the block size + * but not does specify the value of the padding bytes. + */ + if(sslv3_padding) + { + if(padding_length > 0 && padding_length < block_size) + return (padding_length + 1); + else + return 0; + } + + /* + * TLS v1.0 and up require all the padding bytes be the same value + * and allows up to 255 bytes. + */ + const size_t pad_start = record_len - padding_length - 1; + + volatile size_t cmp = 0; + + for(size_t i = 0; i != padding_length; ++i) + cmp += record[pad_start + i] ^ padding_length; + + return cmp ? 0 : padding_length + 1; + } + +void cbc_decrypt_record(byte record_contents[], size_t record_len, + Connection_Cipher_State& cipherstate, + const BlockCipher& bc) + { + const size_t block_size = cipherstate.block_size(); + + BOTAN_ASSERT(record_len % block_size == 0, + "Buffer is an even multiple of block size"); + + const size_t blocks = record_len / block_size; + + BOTAN_ASSERT(blocks >= 1, "At least one ciphertext block"); + + byte* buf = record_contents; + + secure_vector last_ciphertext(block_size); + copy_mem(&last_ciphertext[0], &buf[0], block_size); + + bc.decrypt(&buf[0]); + xor_buf(&buf[0], &cipherstate.cbc_state()[0], block_size); + + secure_vector last_ciphertext2; + + for(size_t i = 1; i < blocks; ++i) + { + last_ciphertext2.assign(&buf[block_size*i], &buf[block_size*(i+1)]); + bc.decrypt(&buf[block_size*i]); + xor_buf(&buf[block_size*i], &last_ciphertext[0], block_size); + std::swap(last_ciphertext, last_ciphertext2); + } + + cipherstate.cbc_state() = last_ciphertext; + } + +void decrypt_record(secure_vector& output, + byte record_contents[], size_t record_len, + u64bit record_sequence, + Protocol_Version record_version, + Record_Type record_type, + Connection_Cipher_State& cipherstate) + { + if(AEAD_Mode* aead = cipherstate.aead()) + { + auto nonce = cipherstate.aead_nonce(record_contents, record_len); + const size_t nonce_length = 8; // fixme, take from ciphersuite + + BOTAN_ASSERT(record_len > nonce_length, "Have data past the nonce"); + const byte* msg = &record_contents[nonce_length]; + const size_t msg_length = record_len - nonce_length; + + const size_t ptext_size = aead->output_length(msg_length); + + aead->set_associated_data_vec( + cipherstate.format_ad(record_sequence, record_type, record_version, ptext_size) + ); + + output += aead->start_vec(nonce); + + const size_t offset = output.size(); + output += std::make_pair(&msg[0], msg_length); + aead->finish(output, offset); + + BOTAN_ASSERT(output.size() == ptext_size + offset, "Produced expected size"); + } + else + { + // GenericBlockCipher / GenericStreamCipher case + + volatile bool padding_bad = false; + size_t pad_size = 0; + + if(StreamCipher* sc = cipherstate.stream_cipher()) + { + sc->cipher1(record_contents, record_len); + // no padding to check or remove + } + else if(BlockCipher* bc = cipherstate.block_cipher()) + { + cbc_decrypt_record(record_contents, record_len, cipherstate, *bc); + + pad_size = tls_padding_check(cipherstate.cipher_padding_single_byte(), + cipherstate.block_size(), + record_contents, record_len); + + padding_bad = (pad_size == 0); + } + else + { + throw Internal_Error("No cipher state set but needed to decrypt"); + } + + const size_t mac_size = cipherstate.mac_size(); + const size_t iv_size = cipherstate.iv_size(); + + const size_t mac_pad_iv_size = mac_size + pad_size + iv_size; + + if(record_len < mac_pad_iv_size) + throw Decoding_Error("Record sent with invalid length"); + + const byte* plaintext_block = &record_contents[iv_size]; + const u16bit plaintext_length = record_len - mac_pad_iv_size; + + cipherstate.mac()->update( + cipherstate.format_ad(record_sequence, record_type, record_version, plaintext_length) + ); + + cipherstate.mac()->update(plaintext_block, plaintext_length); + + std::vector mac_buf(mac_size); + cipherstate.mac()->final(&mac_buf[0]); + + const size_t mac_offset = record_len - (mac_size + pad_size); + + const bool mac_bad = !same_mem(&record_contents[mac_offset], &mac_buf[0], mac_size); + + if(mac_bad || padding_bad) + throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); + + output.assign(plaintext_block, plaintext_block + plaintext_length); + } + } + +} + +size_t read_record(secure_vector& readbuf, + const byte input[], + size_t input_sz, + size_t& consumed, + secure_vector& record, + u64bit* record_sequence, + Protocol_Version* record_version, + Record_Type* record_type, + Connection_Sequence_Numbers* sequence_numbers, + std::function get_cipherstate) + { + consumed = 0; + + if(readbuf.size() < TLS_HEADER_SIZE) // header incomplete? + { + if(size_t needed = fill_buffer_to(readbuf, + input, input_sz, consumed, + TLS_HEADER_SIZE)) + return needed; + + BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, + "Have an entire header"); + } + + // Possible SSLv2 format client hello + if(!sequence_numbers && (readbuf[0] & 0x80) && (readbuf[2] == 1)) + { + if(readbuf[3] == 0 && readbuf[4] == 2) + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Client claims to only support SSLv2, rejecting"); + + if(readbuf[3] >= 3) // SSLv2 mapped TLS hello, then? + { + const size_t record_len = make_u16bit(readbuf[0], readbuf[1]) & 0x7FFF; + + if(size_t needed = fill_buffer_to(readbuf, + input, input_sz, consumed, + record_len + 2)) + return needed; + + BOTAN_ASSERT_EQUAL(readbuf.size(), (record_len + 2), + "Have the entire SSLv2 hello"); + + // Fake v3-style handshake message wrapper + *record_version = Protocol_Version::TLS_V10; + *record_sequence = 0; + *record_type = HANDSHAKE; + + record.resize(4 + readbuf.size() - 2); + + record[0] = CLIENT_HELLO_SSLV2; + record[1] = 0; + record[2] = readbuf[0] & 0x7F; + record[3] = readbuf[1]; + copy_mem(&record[4], &readbuf[2], readbuf.size() - 2); + + readbuf.clear(); + return 0; + } + } + + *record_version = Protocol_Version(readbuf[1], readbuf[2]); + + const bool is_dtls = record_version->is_datagram_protocol(); + + if(is_dtls && readbuf.size() < DTLS_HEADER_SIZE) + { + if(size_t needed = fill_buffer_to(readbuf, + input, input_sz, consumed, + DTLS_HEADER_SIZE)) + return needed; + + BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, + "Have an entire header"); + } + + const size_t header_size = (is_dtls) ? DTLS_HEADER_SIZE : TLS_HEADER_SIZE; + + const size_t record_len = make_u16bit(readbuf[header_size-2], + readbuf[header_size-1]); + + if(record_len > MAX_CIPHERTEXT_SIZE) + throw TLS_Exception(Alert::RECORD_OVERFLOW, + "Got message that exceeds maximum size"); + + if(size_t needed = fill_buffer_to(readbuf, + input, input_sz, consumed, + header_size + record_len)) + return needed; // wrong for DTLS? + + BOTAN_ASSERT_EQUAL(static_cast(header_size) + record_len, + readbuf.size(), + "Have the full record"); + + *record_type = static_cast(readbuf[0]); + + u16bit epoch = 0; + + if(is_dtls) + { + *record_sequence = load_be(&readbuf[3], 0); + epoch = (*record_sequence >> 48); + } + else if(sequence_numbers) + { + *record_sequence = sequence_numbers->next_read_sequence(); + epoch = sequence_numbers->current_read_epoch(); + } + else + { + // server initial handshake case + *record_sequence = 0; + epoch = 0; + } + + if(sequence_numbers && sequence_numbers->already_seen(*record_sequence)) + return 0; + + byte* record_contents = &readbuf[header_size]; + + if(epoch == 0) // Unencrypted initial handshake + { + record.assign(&readbuf[header_size], &readbuf[header_size + record_len]); + readbuf.clear(); + return 0; // got a full record + } + + // Otherwise, decrypt, check MAC, return plaintext + Connection_Cipher_State* cipherstate = get_cipherstate(epoch); + + // FIXME: DTLS reordering might cause us not to have the cipher state + + BOTAN_ASSERT(cipherstate, "Have cipherstate for this epoch"); + + decrypt_record(record, + record_contents, + record_len, + *record_sequence, + *record_version, + *record_type, + *cipherstate); + + if(sequence_numbers) + sequence_numbers->read_accept(*record_sequence); + + readbuf.clear(); + return 0; + } + +} + +} diff --git a/src/lib/tls/tls_record.h b/src/lib/tls/tls_record.h new file mode 100644 index 000000000..ef27a0a02 --- /dev/null +++ b/src/lib/tls/tls_record.h @@ -0,0 +1,135 @@ +/* +* TLS Record Handling +* (C) 2004-2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_RECORDS_H__ +#define BOTAN_TLS_RECORDS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Ciphersuite; +class Session_Keys; + +class Connection_Sequence_Numbers; + +/** +* TLS Cipher State +*/ +class Connection_Cipher_State + { + public: + /** + * Initialize a new cipher state + */ + Connection_Cipher_State(Protocol_Version version, + Connection_Side which_side, + bool is_our_side, + const Ciphersuite& suite, + const Session_Keys& keys); + + AEAD_Mode* aead() { return m_aead.get(); } + + const secure_vector& aead_nonce(u64bit seq); + + const secure_vector& aead_nonce(const byte record[], size_t record_len); + + const secure_vector& format_ad(u64bit seq, byte type, + Protocol_Version version, + u16bit ptext_length); + + BlockCipher* block_cipher() { return m_block_cipher.get(); } + + StreamCipher* stream_cipher() { return m_stream_cipher.get(); } + + MessageAuthenticationCode* mac() { return m_mac.get(); } + + secure_vector& cbc_state() { return m_block_cipher_cbc_state; } + + size_t block_size() const { return m_block_size; } + + size_t mac_size() const { return m_mac->output_length(); } + + size_t iv_size() const { return m_iv_size; } + + bool mac_includes_record_version() const { return !m_is_ssl3; } + + bool cipher_padding_single_byte() const { return m_is_ssl3; } + + bool cbc_without_explicit_iv() const + { return (m_block_size > 0) && (m_iv_size == 0); } + + std::chrono::seconds age() const + { + return std::chrono::duration_cast( + std::chrono::system_clock::now() - m_start_time); + } + + private: + std::chrono::system_clock::time_point m_start_time; + std::unique_ptr m_block_cipher; + secure_vector m_block_cipher_cbc_state; + std::unique_ptr m_stream_cipher; + std::unique_ptr m_mac; + + std::unique_ptr m_aead; + secure_vector m_nonce, m_ad; + + size_t m_block_size = 0; + size_t m_iv_size = 0; + bool m_is_ssl3 = false; + }; + +/** +* Create a TLS record +* @param write_buffer the output record is placed here +* @param msg_type is the type of the message (handshake, alert, ...) +* @param msg is the plaintext message +* @param msg_length is the length of msg +* @param msg_sequence is the sequence number +* @param version is the protocol version +* @param cipherstate is the writing cipher state +* @param rng is a random number generator +* @return number of bytes written to write_buffer +*/ +void write_record(secure_vector& write_buffer, + byte msg_type, const byte msg[], size_t msg_length, + Protocol_Version version, + u64bit msg_sequence, + Connection_Cipher_State* cipherstate, + RandomNumberGenerator& rng); + +/** +* Decode a TLS record +* @return zero if full message, else number of bytes still needed +*/ +size_t read_record(secure_vector& read_buffer, + const byte input[], + size_t input_length, + size_t& input_consumed, + secure_vector& record, + u64bit* record_sequence, + Protocol_Version* record_version, + Record_Type* record_type, + Connection_Sequence_Numbers* sequence_numbers, + std::function get_cipherstate); + +} + +} + +#endif diff --git a/src/lib/tls/tls_seq_numbers.h b/src/lib/tls/tls_seq_numbers.h new file mode 100644 index 000000000..87edf3130 --- /dev/null +++ b/src/lib/tls/tls_seq_numbers.h @@ -0,0 +1,125 @@ +/* +* TLS Sequence Number Handling +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SEQ_NUMBERS_H__ +#define BOTAN_TLS_SEQ_NUMBERS_H__ + +#include +#include + +namespace Botan { + +namespace TLS { + +class Connection_Sequence_Numbers + { + public: + virtual void new_read_cipher_state() = 0; + virtual void new_write_cipher_state() = 0; + + virtual u16bit current_read_epoch() const = 0; + virtual u16bit current_write_epoch() const = 0; + + virtual u64bit next_write_sequence() = 0; + virtual u64bit next_read_sequence() = 0; + + virtual bool already_seen(u64bit seq) const = 0; + virtual void read_accept(u64bit seq) = 0; + }; + +class Stream_Sequence_Numbers : public Connection_Sequence_Numbers + { + public: + void new_read_cipher_state() override { m_read_seq_no = 0; m_read_epoch += 1; } + void new_write_cipher_state() override { m_write_seq_no = 0; m_write_epoch += 1; } + + u16bit current_read_epoch() const override { return m_read_epoch; } + u16bit current_write_epoch() const override { return m_write_epoch; } + + u64bit next_write_sequence() override { return m_write_seq_no++; } + u64bit next_read_sequence() override { return m_read_seq_no; } + + bool already_seen(u64bit) const override { return false; } + void read_accept(u64bit) override { m_read_seq_no++; } + private: + u64bit m_write_seq_no = 0; + u64bit m_read_seq_no = 0; + u16bit m_read_epoch = 0; + u16bit m_write_epoch = 0; + }; + +class Datagram_Sequence_Numbers : public Connection_Sequence_Numbers + { + public: + void new_read_cipher_state() override { m_read_epoch += 1; } + + void new_write_cipher_state() override + { + // increment epoch + m_write_seq_no = ((m_write_seq_no >> 48) + 1) << 48; + } + + u16bit current_read_epoch() const override { return m_read_epoch; } + u16bit current_write_epoch() const override { return (m_write_seq_no >> 48); } + + u64bit next_write_sequence() override { return m_write_seq_no++; } + + u64bit next_read_sequence() override + { + throw std::runtime_error("DTLS uses explicit sequence numbers"); + } + + bool already_seen(u64bit sequence) const override + { + const size_t window_size = sizeof(m_window_bits) * 8; + + if(sequence > m_window_highest) + return false; + + const u64bit offset = m_window_highest - sequence; + + if(offset >= window_size) + return true; // really old? + + return (((m_window_bits >> offset) & 1) == 1); + } + + void read_accept(u64bit sequence) override + { + const size_t window_size = sizeof(m_window_bits) * 8; + + if(sequence > m_window_highest) + { + const size_t offset = sequence - m_window_highest; + m_window_highest += offset; + + if(offset >= window_size) + m_window_bits = 0; + else + m_window_bits <<= offset; + + m_window_bits |= 0x01; + } + else + { + const u64bit offset = m_window_highest - sequence; + m_window_bits |= (static_cast(1) << offset); + } + } + + private: + u64bit m_write_seq_no = 0; + u16bit m_read_epoch = 0; + u64bit m_window_highest = 0; + u64bit m_window_bits = 0; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp new file mode 100644 index 000000000..bc518571b --- /dev/null +++ b/src/lib/tls/tls_server.cpp @@ -0,0 +1,725 @@ +/* +* TLS Server +* (C) 2004-2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +class Server_Handshake_State : public Handshake_State + { + public: + // using Handshake_State::Handshake_State; + + Server_Handshake_State(Handshake_IO* io) : Handshake_State(io) {} + + // Used by the server only, in case of RSA key exchange. Not owned + Private_Key* server_rsa_kex_key = nullptr; + + /* + * Used by the server to know if resumption should be allowed on + * a server-initiated renegotiation + */ + bool allow_session_resumption = true; + }; + +bool check_for_resume(Session& session_info, + Session_Manager& session_manager, + Credentials_Manager& credentials, + const Client_Hello* client_hello, + std::chrono::seconds session_ticket_lifetime) + { + const std::vector& client_session_id = client_hello->session_id(); + const std::vector& session_ticket = client_hello->session_ticket(); + + if(session_ticket.empty()) + { + if(client_session_id.empty()) // not resuming + return false; + + // not found + if(!session_manager.load_from_session_id(client_session_id, session_info)) + return false; + } + else + { + // If a session ticket was sent, ignore client session ID + try + { + session_info = Session::decrypt( + session_ticket, + credentials.psk("tls-server", "session-ticket", "")); + + if(session_ticket_lifetime != std::chrono::seconds(0) && + session_info.session_age() > session_ticket_lifetime) + return false; // ticket has expired + } + catch(...) + { + return false; + } + } + + // wrong version + if(client_hello->version() != session_info.version()) + return false; + + // client didn't send original ciphersuite + if(!value_exists(client_hello->ciphersuites(), + session_info.ciphersuite_code())) + return false; + + // client didn't send original compression method + if(!value_exists(client_hello->compression_methods(), + session_info.compression_method())) + return false; + + // client sent a different SRP identity + if(client_hello->srp_identifier() != "") + { + if(client_hello->srp_identifier() != session_info.srp_identifier()) + return false; + } + + // client sent a different SNI hostname + if(client_hello->sni_hostname() != "") + { + if(client_hello->sni_hostname() != session_info.server_info().hostname()) + return false; + } + + return true; + } + +/* +* Choose which ciphersuite to use +*/ +u16bit choose_ciphersuite( + const Policy& policy, + Protocol_Version version, + Credentials_Manager& creds, + const std::map >& cert_chains, + const Client_Hello* client_hello) + { + const bool our_choice = policy.server_uses_own_ciphersuite_preferences(); + + const bool have_srp = creds.attempt_srp("tls-server", + client_hello->sni_hostname()); + + const std::vector client_suites = client_hello->ciphersuites(); + + const std::vector server_suites = policy.ciphersuite_list(version, have_srp); + + if(server_suites.empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Policy forbids us from negotiating any ciphersuite"); + + const bool have_shared_ecc_curve = + (policy.choose_curve(client_hello->supported_ecc_curves()) != ""); + + std::vector pref_list = server_suites; + std::vector other_list = client_suites; + + if(!our_choice) + std::swap(pref_list, other_list); + + for(auto suite_id : pref_list) + { + if(!value_exists(other_list, suite_id)) + continue; + + Ciphersuite suite = Ciphersuite::by_id(suite_id); + + if(!have_shared_ecc_curve && suite.ecc_ciphersuite()) + continue; + + if(suite.sig_algo() != "" && cert_chains.count(suite.sig_algo()) == 0) + continue; + + /* + The client may offer SRP cipher suites in the hello message but + omit the SRP extension. If the server would like to select an + SRP cipher suite in this case, the server SHOULD return a fatal + "unknown_psk_identity" alert immediately after processing the + client hello message. + - RFC 5054 section 2.5.1.2 + */ + if(suite.kex_algo() == "SRP_SHA" && client_hello->srp_identifier() == "") + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "Client wanted SRP but did not send username"); + + return suite_id; + } + + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Can't agree on a ciphersuite with client"); + } + + +/* +* Choose which compression algorithm to use +*/ +byte choose_compression(const Policy& policy, + const std::vector& c_comp) + { + std::vector s_comp = policy.compression(); + + for(size_t i = 0; i != s_comp.size(); ++i) + for(size_t j = 0; j != c_comp.size(); ++j) + if(s_comp[i] == c_comp[j]) + return s_comp[i]; + + return NO_COMPRESSION; + } + +std::map > +get_server_certs(const std::string& hostname, + Credentials_Manager& creds) + { + const char* cert_types[] = { "RSA", "DSA", "ECDSA", nullptr }; + + std::map > cert_chains; + + for(size_t i = 0; cert_types[i]; ++i) + { + std::vector certs = + creds.cert_chain_single_type(cert_types[i], "tls-server", hostname); + + if(!certs.empty()) + cert_chains[cert_types[i]] = certs; + } + + return cert_chains; + } + +} + +/* +* TLS Server Constructor +*/ +Server::Server(std::function output_fn, + std::function data_cb, + std::function alert_cb, + std::function handshake_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const std::vector& next_protocols, + size_t io_buf_sz) : + Channel(output_fn, data_cb, alert_cb, handshake_cb, session_manager, rng, io_buf_sz), + m_policy(policy), + m_creds(creds), + m_possible_protocols(next_protocols) + { + } + +Handshake_State* Server::new_handshake_state(Handshake_IO* io) + { + std::unique_ptr state(new Server_Handshake_State(io)); + state->set_expected_next(CLIENT_HELLO); + return state.release(); + } + +std::vector +Server::get_peer_cert_chain(const Handshake_State& state) const + { + if(state.client_certs()) + return state.client_certs()->cert_chain(); + return std::vector(); + } + +/* +* Send a hello request to the client +*/ +void Server::initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) + { + dynamic_cast(state).allow_session_resumption = + !force_full_renegotiation; + + Hello_Request hello_req(state.handshake_io()); + } + +/* +* Process a handshake message +*/ +void Server::process_handshake_msg(const Handshake_State* active_state, + Handshake_State& state_base, + Handshake_Type type, + const std::vector& contents) + { + Server_Handshake_State& state = dynamic_cast(state_base); + + state.confirm_transition_to(type); + + /* + * The change cipher spec message isn't technically a handshake + * message so it's not included in the hash. The finished and + * certificate verify messages are verified based on the current + * state of the hash *before* this message so we delay adding them + * to the hash computation until we've processed them below. + */ + if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY) + { + if(type == CLIENT_HELLO_SSLV2) + state.hash().update(contents); + else + state.hash().update(state.handshake_io().format(contents, type)); + } + + if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) + { + const bool initial_handshake = !active_state; + + if(!m_policy.allow_insecure_renegotiation() && + !(initial_handshake || secure_renegotiation_supported())) + { + send_warning_alert(Alert::NO_RENEGOTIATION); + return; + } + + state.client_hello(new Client_Hello(contents, type)); + + Protocol_Version client_version = state.client_hello()->version(); + + Protocol_Version negotiated_version; + + if((initial_handshake && client_version.known_version()) || + (!initial_handshake && client_version == active_state->version())) + { + /* + Common cases: new client hello with some known version, or a + renegotiation using the same version as previously + negotiated. + */ + + negotiated_version = client_version; + } + else if(!initial_handshake && (client_version != active_state->version())) + { + /* + * If this is a renegotiation, and the client has offered a + * later version than what it initially negotiated, negotiate + * the old version. This matches OpenSSL's behavior. If the + * client is offering a version earlier than what it initially + * negotiated, reject as a probable attack. + */ + if(active_state->version() > client_version) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Client negotiated " + + active_state->version().to_string() + + " then renegotiated with " + + client_version.to_string()); + } + else + negotiated_version = active_state->version(); + } + else + { + /* + New negotiation using a version we don't know. Offer + them the best we currently know. + */ + negotiated_version = client_version.best_known_match(); + } + + if(!m_policy.acceptable_protocol_version(negotiated_version)) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Client version is unacceptable by policy"); + } + + if(!initial_handshake && state.client_hello()->next_protocol_notification()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client included NPN extension for renegotiation"); + + secure_renegotiation_check(state.client_hello()); + + state.set_version(negotiated_version); + + Session session_info; + const bool resuming = + state.allow_session_resumption && + check_for_resume(session_info, + session_manager(), + m_creds, + state.client_hello(), + std::chrono::seconds(m_policy.session_ticket_lifetime())); + + bool have_session_ticket_key = false; + + try + { + have_session_ticket_key = + m_creds.psk("tls-server", "session-ticket", "").length() > 0; + } + catch(...) {} + + if(resuming) + { + // resume session + + const bool offer_new_session_ticket = + (state.client_hello()->supports_session_ticket() && + state.client_hello()->session_ticket().empty() && + have_session_ticket_key); + + state.server_hello( + new Server_Hello( + state.handshake_io(), + state.hash(), + m_policy, + state.client_hello()->session_id(), + Protocol_Version(session_info.version()), + session_info.ciphersuite_code(), + session_info.compression_method(), + session_info.fragment_size(), + state.client_hello()->secure_renegotiation(), + secure_renegotiation_data_for_server_hello(), + offer_new_session_ticket, + state.client_hello()->next_protocol_notification(), + m_possible_protocols, + state.client_hello()->supports_heartbeats(), + rng()) + ); + + secure_renegotiation_check(state.server_hello()); + + state.compute_session_keys(session_info.master_secret()); + + if(!save_session(session_info)) + { + session_manager().remove_entry(session_info.session_id()); + + if(state.server_hello()->supports_session_ticket()) // send an empty ticket + { + state.new_session_ticket( + new New_Session_Ticket(state.handshake_io(), + state.hash()) + ); + } + } + + if(state.server_hello()->supports_session_ticket() && !state.new_session_ticket()) + { + try + { + const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); + + state.new_session_ticket( + new New_Session_Ticket(state.handshake_io(), + state.hash(), + session_info.encrypt(ticket_key, rng()), + m_policy.session_ticket_lifetime()) + ); + } + catch(...) {} + + if(!state.new_session_ticket()) + { + state.new_session_ticket( + new New_Session_Ticket(state.handshake_io(), state.hash()) + ); + } + } + + state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(SERVER); + + state.server_finished( + new Finished(state.handshake_io(), state, SERVER) + ); + + state.set_expected_next(HANDSHAKE_CCS); + } + else // new session + { + std::map > cert_chains; + + const std::string sni_hostname = state.client_hello()->sni_hostname(); + + cert_chains = get_server_certs(sni_hostname, m_creds); + + if(sni_hostname != "" && cert_chains.empty()) + { + cert_chains = get_server_certs("", m_creds); + + /* + * Only send the unrecognized_name alert if we couldn't + * find any certs for the requested name but did find at + * least one cert to use in general. That avoids sending an + * unrecognized_name when a server is configured for purely + * anonymous operation. + */ + if(!cert_chains.empty()) + send_alert(Alert(Alert::UNRECOGNIZED_NAME)); + } + + state.server_hello( + new Server_Hello( + state.handshake_io(), + state.hash(), + m_policy, + make_hello_random(rng()), // new session ID + state.version(), + choose_ciphersuite(m_policy, + state.version(), + m_creds, + cert_chains, + state.client_hello()), + choose_compression(m_policy, state.client_hello()->compression_methods()), + state.client_hello()->fragment_size(), + state.client_hello()->secure_renegotiation(), + secure_renegotiation_data_for_server_hello(), + state.client_hello()->supports_session_ticket() && have_session_ticket_key, + state.client_hello()->next_protocol_notification(), + m_possible_protocols, + state.client_hello()->supports_heartbeats(), + rng()) + ); + + secure_renegotiation_check(state.server_hello()); + + const std::string sig_algo = state.ciphersuite().sig_algo(); + const std::string kex_algo = state.ciphersuite().kex_algo(); + + if(sig_algo != "") + { + BOTAN_ASSERT(!cert_chains[sig_algo].empty(), + "Attempting to send empty certificate chain"); + + state.server_certs( + new Certificate(state.handshake_io(), + state.hash(), + cert_chains[sig_algo]) + ); + } + + Private_Key* private_key = nullptr; + + if(kex_algo == "RSA" || sig_algo != "") + { + private_key = m_creds.private_key_for( + state.server_certs()->cert_chain()[0], + "tls-server", + sni_hostname); + + if(!private_key) + throw Internal_Error("No private key located for associated server cert"); + } + + if(kex_algo == "RSA") + { + state.server_rsa_kex_key = private_key; + } + else + { + state.server_kex( + new Server_Key_Exchange(state.handshake_io(), + state, + m_policy, + m_creds, + rng(), + private_key) + ); + } + + auto trusted_CAs = + m_creds.trusted_certificate_authorities("tls-server", sni_hostname); + + std::vector client_auth_CAs; + + for(auto store : trusted_CAs) + { + auto subjects = store->all_subjects(); + client_auth_CAs.insert(client_auth_CAs.end(), + subjects.begin(), + subjects.end()); + } + + if(!client_auth_CAs.empty() && state.ciphersuite().sig_algo() != "") + { + state.cert_req( + new Certificate_Req(state.handshake_io(), + state.hash(), + m_policy, + client_auth_CAs, + state.version()) + ); + + state.set_expected_next(CERTIFICATE); + } + + /* + * If the client doesn't have a cert they want to use they are + * allowed to send either an empty cert message or proceed + * directly to the client key exchange, so allow either case. + */ + state.set_expected_next(CLIENT_KEX); + + state.server_hello_done( + new Server_Hello_Done(state.handshake_io(), state.hash()) + ); + } + } + else if(type == CERTIFICATE) + { + state.client_certs(new Certificate(contents)); + + state.set_expected_next(CLIENT_KEX); + } + else if(type == CLIENT_KEX) + { + if(state.received_handshake_msg(CERTIFICATE) && !state.client_certs()->empty()) + state.set_expected_next(CERTIFICATE_VERIFY); + else + state.set_expected_next(HANDSHAKE_CCS); + + state.client_kex( + new Client_Key_Exchange(contents, state, + state.server_rsa_kex_key, + m_creds, m_policy, rng()) + ); + + state.compute_session_keys(); + } + else if(type == CERTIFICATE_VERIFY) + { + state.client_verify(new Certificate_Verify(contents, state.version())); + + const std::vector& client_certs = + state.client_certs()->cert_chain(); + + const bool sig_valid = + state.client_verify()->verify(client_certs[0], state); + + state.hash().update(state.handshake_io().format(contents, type)); + + /* + * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for + * "A handshake cryptographic operation failed, including being + * unable to correctly verify a signature, ..." + */ + if(!sig_valid) + throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed"); + + try + { + m_creds.verify_certificate_chain("tls-server", "", client_certs); + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); + } + + state.set_expected_next(HANDSHAKE_CCS); + } + else if(type == HANDSHAKE_CCS) + { + if(state.server_hello()->next_protocol_notification()) + state.set_expected_next(NEXT_PROTOCOL); + else + state.set_expected_next(FINISHED); + + change_cipher_spec_reader(SERVER); + } + else if(type == NEXT_PROTOCOL) + { + state.set_expected_next(FINISHED); + + state.next_protocol(new Next_Protocol(contents)); + + // should this be a callback? + m_next_protocol = state.next_protocol()->protocol(); + } + else if(type == FINISHED) + { + state.set_expected_next(HANDSHAKE_NONE); + + state.client_finished(new Finished(contents)); + + if(!state.client_finished()->verify(state, CLIENT)) + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Finished message didn't verify"); + + if(!state.server_finished()) + { + // already sent finished if resuming, so this is a new session + + state.hash().update(state.handshake_io().format(contents, type)); + + Session session_info( + state.server_hello()->session_id(), + state.session_keys().master_secret(), + state.server_hello()->version(), + state.server_hello()->ciphersuite(), + state.server_hello()->compression_method(), + SERVER, + state.server_hello()->fragment_size(), + get_peer_cert_chain(state), + std::vector(), + Server_Information(state.client_hello()->sni_hostname()), + state.srp_identifier() + ); + + if(save_session(session_info)) + { + if(state.server_hello()->supports_session_ticket()) + { + try + { + const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); + + state.new_session_ticket( + new New_Session_Ticket(state.handshake_io(), + state.hash(), + session_info.encrypt(ticket_key, rng()), + m_policy.session_ticket_lifetime()) + ); + } + catch(...) {} + } + else + session_manager().save(session_info); + } + + if(!state.new_session_ticket() && + state.server_hello()->supports_session_ticket()) + { + state.new_session_ticket( + new New_Session_Ticket(state.handshake_io(), state.hash()) + ); + } + + state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(SERVER); + + state.server_finished( + new Finished(state.handshake_io(), state, SERVER) + ); + } + + activate_session(); + } + else + throw Unexpected_Message("Unknown handshake message received"); + } + +} + +} diff --git a/src/lib/tls/tls_server.h b/src/lib/tls/tls_server.h new file mode 100644 index 000000000..a514607ba --- /dev/null +++ b/src/lib/tls/tls_server.h @@ -0,0 +1,71 @@ +/* +* TLS Server +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SERVER_H__ +#define BOTAN_TLS_SERVER_H__ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Server +*/ +class BOTAN_DLL Server : public Channel + { + public: + /** + * Server initialization + */ + Server(std::function socket_output_fn, + std::function data_cb, + std::function alert_cb, + std::function handshake_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const std::vector& protocols = std::vector(), + size_t reserved_io_buffer_size = 16*1024 + ); + + /** + * Return the protocol notification set by the client (using the + * NPN extension) for this connection, if any + */ + std::string next_protocol() const { return m_next_protocol; } + + private: + std::vector + get_peer_cert_chain(const Handshake_State& state) const override; + + void initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) override; + + void process_handshake_msg(const Handshake_State* active_state, + Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents) override; + + Handshake_State* new_handshake_state(Handshake_IO* io) override; + + const Policy& m_policy; + Credentials_Manager& m_creds; + + std::vector m_possible_protocols; + std::string m_next_protocol; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_server_info.h b/src/lib/tls/tls_server_info.h new file mode 100644 index 000000000..773296eaf --- /dev/null +++ b/src/lib/tls/tls_server_info.h @@ -0,0 +1,91 @@ +/* +* TLS Server Information +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SERVER_INFO_H__ +#define BOTAN_TLS_SERVER_INFO_H__ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Represents information known about a TLS server. +*/ +class BOTAN_DLL Server_Information + { + public: + /** + * An empty server info - nothing known + */ + Server_Information() : m_hostname(""), m_service(""), m_port(0) {} + + /** + * @param hostname the host's DNS name, if known + * @param port specifies the protocol port of the server (eg for + * TCP/UDP). Zero represents unknown. + */ + Server_Information(const std::string& hostname, + u16bit port = 0) : + m_hostname(hostname), m_service(""), m_port(port) {} + + /** + * @param hostname the host's DNS name, if known + * @param service is a text string of the service type + * (eg "https", "tor", or "git") + * @param port specifies the protocol port of the server (eg for + * TCP/UDP). Zero represents unknown. + */ + Server_Information(const std::string& hostname, + const std::string& service, + u16bit port = 0) : + m_hostname(hostname), m_service(service), m_port(port) {} + + std::string hostname() const { return m_hostname; } + + std::string service() const { return m_service; } + + u16bit port() const { return m_port; } + + bool empty() const { return m_hostname.empty(); } + + private: + std::string m_hostname, m_service; + u16bit m_port; + }; + +inline bool operator==(const Server_Information& a, const Server_Information& b) + { + return (a.hostname() == b.hostname()) && + (a.service() == b.service()) && + (a.port() == b.port()); + + } + +inline bool operator!=(const Server_Information& a, const Server_Information& b) + { + return !(a == b); + } + +inline bool operator<(const Server_Information& a, const Server_Information& b) + { + if(a.hostname() != b.hostname()) + return (a.hostname() < b.hostname()); + if(a.service() != b.service()) + return (a.service() < b.service()); + if(a.port() != b.port()) + return (a.port() < b.port()); + return false; // equal + } + +} + +} + +#endif diff --git a/src/lib/tls/tls_session.cpp b/src/lib/tls/tls_session.cpp new file mode 100644 index 000000000..6596804b5 --- /dev/null +++ b/src/lib/tls/tls_session.cpp @@ -0,0 +1,177 @@ +/* +* TLS Session State +* (C) 2011-2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Session::Session(const std::vector& session_identifier, + const secure_vector& master_secret, + Protocol_Version version, + u16bit ciphersuite, + byte compression_method, + Connection_Side side, + size_t fragment_size, + const std::vector& certs, + const std::vector& ticket, + const Server_Information& server_info, + const std::string& srp_identifier) : + m_start_time(std::chrono::system_clock::now()), + m_identifier(session_identifier), + m_session_ticket(ticket), + m_master_secret(master_secret), + m_version(version), + m_ciphersuite(ciphersuite), + m_compression_method(compression_method), + m_connection_side(side), + m_fragment_size(fragment_size), + m_peer_certs(certs), + m_server_info(server_info), + m_srp_identifier(srp_identifier) + { + } + +Session::Session(const std::string& pem) + { + secure_vector der = PEM_Code::decode_check_label(pem, "SSL SESSION"); + + *this = Session(&der[0], der.size()); + } + +Session::Session(const byte ber[], size_t ber_len) + { + byte side_code = 0; + + ASN1_String server_hostname; + ASN1_String server_service; + size_t server_port; + + ASN1_String srp_identifier_str; + + byte major_version = 0, minor_version = 0; + + std::vector peer_cert_bits; + + size_t start_time = 0; + + BER_Decoder(ber, ber_len) + .start_cons(SEQUENCE) + .decode_and_check(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION), + "Unknown version in session structure") + .decode_integer_type(start_time) + .decode_integer_type(major_version) + .decode_integer_type(minor_version) + .decode(m_identifier, OCTET_STRING) + .decode(m_session_ticket, OCTET_STRING) + .decode_integer_type(m_ciphersuite) + .decode_integer_type(m_compression_method) + .decode_integer_type(side_code) + .decode_integer_type(m_fragment_size) + .decode(m_master_secret, OCTET_STRING) + .decode(peer_cert_bits, OCTET_STRING) + .decode(server_hostname) + .decode(server_service) + .decode(server_port) + .decode(srp_identifier_str) + .end_cons() + .verify_end(); + + m_version = Protocol_Version(major_version, minor_version); + m_start_time = std::chrono::system_clock::from_time_t(start_time); + m_connection_side = static_cast(side_code); + + m_server_info = Server_Information(server_hostname.value(), + server_service.value(), + server_port); + + m_srp_identifier = srp_identifier_str.value(); + + if(!peer_cert_bits.empty()) + { + DataSource_Memory certs(&peer_cert_bits[0], peer_cert_bits.size()); + + while(!certs.end_of_data()) + m_peer_certs.push_back(X509_Certificate(certs)); + } + } + +secure_vector Session::DER_encode() const + { + std::vector peer_cert_bits; + for(size_t i = 0; i != m_peer_certs.size(); ++i) + peer_cert_bits += m_peer_certs[i].BER_encode(); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION)) + .encode(static_cast(std::chrono::system_clock::to_time_t(m_start_time))) + .encode(static_cast(m_version.major_version())) + .encode(static_cast(m_version.minor_version())) + .encode(m_identifier, OCTET_STRING) + .encode(m_session_ticket, OCTET_STRING) + .encode(static_cast(m_ciphersuite)) + .encode(static_cast(m_compression_method)) + .encode(static_cast(m_connection_side)) + .encode(static_cast(m_fragment_size)) + .encode(m_master_secret, OCTET_STRING) + .encode(peer_cert_bits, OCTET_STRING) + .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING)) + .encode(ASN1_String(m_server_info.service(), UTF8_STRING)) + .encode(static_cast(m_server_info.port())) + .encode(ASN1_String(m_srp_identifier, UTF8_STRING)) + .end_cons() + .get_contents(); + } + +std::string Session::PEM_encode() const + { + return PEM_Code::encode(this->DER_encode(), "SSL SESSION"); + } + +std::chrono::seconds Session::session_age() const + { + return std::chrono::duration_cast( + std::chrono::system_clock::now() - m_start_time); + } + +std::vector +Session::encrypt(const SymmetricKey& master_key, + RandomNumberGenerator& rng) const + { + const auto der = this->DER_encode(); + + return CryptoBox::encrypt(&der[0], der.size(), master_key, rng); + } + +Session Session::decrypt(const byte buf[], size_t buf_len, + const SymmetricKey& master_key) + { + try + { + const auto ber = CryptoBox::decrypt(buf, buf_len, master_key); + + return Session(&ber[0], ber.size()); + } + catch(std::exception& e) + { + throw Decoding_Error("Failed to decrypt encrypted session -" + + std::string(e.what())); + } + } + +} + +} + diff --git a/src/lib/tls/tls_session.h b/src/lib/tls/tls_session.h new file mode 100644 index 000000000..65154dfce --- /dev/null +++ b/src/lib/tls/tls_session.h @@ -0,0 +1,206 @@ +/* +* TLS Session +* (C) 2011-2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SESSION_STATE_H__ +#define BOTAN_TLS_SESSION_STATE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Class representing a TLS session state +*/ +class BOTAN_DLL Session + { + public: + + /** + * Uninitialized session + */ + Session() : + m_start_time(std::chrono::system_clock::time_point::min()), + m_version(), + m_ciphersuite(0), + m_compression_method(0), + m_connection_side(static_cast(0)), + m_fragment_size(0) + {} + + /** + * New session (sets session start time) + */ + Session(const std::vector& session_id, + const secure_vector& master_secret, + Protocol_Version version, + u16bit ciphersuite, + byte compression_method, + Connection_Side side, + size_t fragment_size, + const std::vector& peer_certs, + const std::vector& session_ticket, + const Server_Information& server_info, + const std::string& srp_identifier); + + /** + * Load a session from DER representation (created by DER_encode) + */ + Session(const byte ber[], size_t ber_len); + + /** + * Load a session from PEM representation (created by PEM_encode) + */ + Session(const std::string& pem); + + /** + * Encode this session data for storage + * @warning if the master secret is compromised so is the + * session traffic + */ + secure_vector DER_encode() const; + + /** + * Encrypt a session (useful for serialization or session tickets) + */ + std::vector encrypt(const SymmetricKey& key, + RandomNumberGenerator& rng) const; + + + /** + * Decrypt a session created by encrypt + * @param ctext the ciphertext returned by encrypt + * @param ctext_size the size of ctext in bytes + * @param key the same key used by the encrypting side + */ + static Session decrypt(const byte ctext[], + size_t ctext_size, + const SymmetricKey& key); + + /** + * Decrypt a session created by encrypt + * @param ctext the ciphertext returned by encrypt + * @param key the same key used by the encrypting side + */ + static inline Session decrypt(const std::vector& ctext, + const SymmetricKey& key) + { + return Session::decrypt(&ctext[0], ctext.size(), key); + } + + /** + * Encode this session data for storage + * @warning if the master secret is compromised so is the + * session traffic + */ + std::string PEM_encode() const; + + /** + * Get the version of the saved session + */ + Protocol_Version version() const { return m_version; } + + /** + * Get the ciphersuite code of the saved session + */ + u16bit ciphersuite_code() const { return m_ciphersuite; } + + /** + * Get the ciphersuite info of the saved session + */ + Ciphersuite ciphersuite() const { return Ciphersuite::by_id(m_ciphersuite); } + + /** + * Get the compression method used in the saved session + */ + byte compression_method() const { return m_compression_method; } + + /** + * Get which side of the connection the resumed session we are/were + * acting as. + */ + Connection_Side side() const { return m_connection_side; } + + /** + * Get the SRP identity (if sent by the client in the initial handshake) + */ + std::string srp_identifier() const { return m_srp_identifier; } + + /** + * Get the saved master secret + */ + const secure_vector& master_secret() const + { return m_master_secret; } + + /** + * Get the session identifier + */ + const std::vector& session_id() const + { return m_identifier; } + + /** + * Get the negotiated maximum fragment size (or 0 if default) + */ + size_t fragment_size() const { return m_fragment_size; } + + /** + * Return the certificate chain of the peer (possibly empty) + */ + std::vector peer_certs() const { return m_peer_certs; } + + /** + * Get the wall clock time this session began + */ + std::chrono::system_clock::time_point start_time() const + { return m_start_time; } + + /** + * Return how long this session has existed (in seconds) + */ + std::chrono::seconds session_age() const; + + /** + * Return the session ticket the server gave us + */ + const std::vector& session_ticket() const { return m_session_ticket; } + + Server_Information server_info() const { return m_server_info; } + + private: + enum { TLS_SESSION_PARAM_STRUCT_VERSION = 0x2994e301 }; + + std::chrono::system_clock::time_point m_start_time; + + std::vector m_identifier; + std::vector m_session_ticket; // only used by client side + secure_vector m_master_secret; + + Protocol_Version m_version; + u16bit m_ciphersuite; + byte m_compression_method; + Connection_Side m_connection_side; + + size_t m_fragment_size; + + std::vector m_peer_certs; + Server_Information m_server_info; // optional + std::string m_srp_identifier; // optional + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_session_key.cpp b/src/lib/tls/tls_session_key.cpp new file mode 100644 index 000000000..06cd1d0a1 --- /dev/null +++ b/src/lib/tls/tls_session_key.cpp @@ -0,0 +1,86 @@ +/* +* TLS Session Key +* (C) 2004-2006,2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Session_Keys Constructor +*/ +Session_Keys::Session_Keys(const Handshake_State* state, + const secure_vector& pre_master_secret, + bool resuming) + { + const size_t cipher_keylen = state->ciphersuite().cipher_keylen(); + const size_t mac_keylen = state->ciphersuite().mac_keylen(); + const size_t cipher_ivlen = state->ciphersuite().cipher_ivlen(); + + const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_ivlen); + + const byte MASTER_SECRET_MAGIC[] = { + 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 }; + + const byte KEY_GEN_MAGIC[] = { + 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, 0x6E }; + + std::unique_ptr prf(state->protocol_specific_prf()); + + if(resuming) + { + master_sec = pre_master_secret; + } + else + { + secure_vector salt; + + if(state->version() != Protocol_Version::SSL_V3) + salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC)); + + salt += state->client_hello()->random(); + salt += state->server_hello()->random(); + + master_sec = prf->derive_key(48, pre_master_secret, salt); + } + + secure_vector salt; + if(state->version() != Protocol_Version::SSL_V3) + salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC)); + salt += state->server_hello()->random(); + salt += state->client_hello()->random(); + + SymmetricKey keyblock = prf->derive_key(prf_gen, master_sec, salt); + + const byte* key_data = keyblock.begin(); + + c_mac = SymmetricKey(key_data, mac_keylen); + key_data += mac_keylen; + + s_mac = SymmetricKey(key_data, mac_keylen); + key_data += mac_keylen; + + c_cipher = SymmetricKey(key_data, cipher_keylen); + key_data += cipher_keylen; + + s_cipher = SymmetricKey(key_data, cipher_keylen); + key_data += cipher_keylen; + + c_iv = InitializationVector(key_data, cipher_ivlen); + key_data += cipher_ivlen; + + s_iv = InitializationVector(key_data, cipher_ivlen); + } + +} + +} diff --git a/src/lib/tls/tls_session_key.h b/src/lib/tls/tls_session_key.h new file mode 100644 index 000000000..d62e3400d --- /dev/null +++ b/src/lib/tls/tls_session_key.h @@ -0,0 +1,50 @@ +/* +* TLS Session Key +* (C) 2004-2006,2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SESSION_KEYS_H__ +#define BOTAN_TLS_SESSION_KEYS_H__ + +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Session Keys +*/ +class Session_Keys + { + public: + SymmetricKey client_cipher_key() const { return c_cipher; } + SymmetricKey server_cipher_key() const { return s_cipher; } + + SymmetricKey client_mac_key() const { return c_mac; } + SymmetricKey server_mac_key() const { return s_mac; } + + InitializationVector client_iv() const { return c_iv; } + InitializationVector server_iv() const { return s_iv; } + + const secure_vector& master_secret() const { return master_sec; } + + Session_Keys() {} + + Session_Keys(const class Handshake_State* state, + const secure_vector& pre_master, + bool resuming); + + private: + secure_vector master_sec; + SymmetricKey c_cipher, s_cipher, c_mac, s_mac; + InitializationVector c_iv, s_iv; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_session_manager.h b/src/lib/tls/tls_session_manager.h new file mode 100644 index 000000000..e6eacc88c --- /dev/null +++ b/src/lib/tls/tls_session_manager.h @@ -0,0 +1,149 @@ +/* +* TLS Session Manager +* (C) 2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SESSION_MANAGER_H__ +#define BOTAN_TLS_SESSION_MANAGER_H__ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Session_Manager is an interface to systems which can save +* session parameters for supporting session resumption. +* +* Saving sessions is done on a best-effort basis; an implementation is +* allowed to drop sessions due to space constraints. +* +* Implementations should strive to be thread safe +*/ +class BOTAN_DLL Session_Manager + { + public: + /** + * Try to load a saved session (using session ID) + * @param session_id the session identifier we are trying to resume + * @param session will be set to the saved session data (if found), + or not modified if not found + * @return true if session was modified + */ + virtual bool load_from_session_id(const std::vector& session_id, + Session& session) = 0; + + /** + * Try to load a saved session (using info about server) + * @param info the information about the server + * @param session will be set to the saved session data (if found), + or not modified if not found + * @return true if session was modified + */ + virtual bool load_from_server_info(const Server_Information& info, + Session& session) = 0; + + /** + * Remove this session id from the cache, if it exists + */ + virtual void remove_entry(const std::vector& session_id) = 0; + + /** + * Save a session on a best effort basis; the manager may not in + * fact be able to save the session for whatever reason; this is + * not an error. Caller cannot assume that calling save followed + * immediately by load_from_* will result in a successful lookup. + * + * @param session to save + */ + virtual void save(const Session& session) = 0; + + /** + * Return the allowed lifetime of a session; beyond this time, + * sessions are not resumed. Returns 0 if unknown/no explicit + * expiration policy. + */ + virtual std::chrono::seconds session_lifetime() const = 0; + + virtual ~Session_Manager() {} + }; + +/** +* An implementation of Session_Manager that does not save sessions at +* all, preventing session resumption. +*/ +class BOTAN_DLL Session_Manager_Noop : public Session_Manager + { + public: + bool load_from_session_id(const std::vector&, Session&) override + { return false; } + + bool load_from_server_info(const Server_Information&, Session&) override + { return false; } + + void remove_entry(const std::vector&) override {} + + void save(const Session&) override {} + + std::chrono::seconds session_lifetime() const override + { return std::chrono::seconds(0); } + }; + +/** +* An implementation of Session_Manager that saves values in memory. +*/ +class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager + { + public: + /** + * @param max_sessions a hint on the maximum number of sessions + * to keep in memory at any one time. (If zero, don't cap) + * @param session_lifetime sessions are expired after this many + * seconds have elapsed from initial handshake. + */ + Session_Manager_In_Memory(RandomNumberGenerator& rng, + size_t max_sessions = 1000, + std::chrono::seconds session_lifetime = + std::chrono::seconds(7200)); + + bool load_from_session_id(const std::vector& session_id, + Session& session) override; + + bool load_from_server_info(const Server_Information& info, + Session& session) override; + + void remove_entry(const std::vector& session_id) override; + + void save(const Session& session_data) override; + + std::chrono::seconds session_lifetime() const override + { return m_session_lifetime; } + + private: + bool load_from_session_str(const std::string& session_str, + Session& session); + + std::mutex m_mutex; + + size_t m_max_sessions; + + std::chrono::seconds m_session_lifetime; + + RandomNumberGenerator& m_rng; + SymmetricKey m_session_key; + + std::map> m_sessions; // hex(session_id) -> session + std::map m_info_sessions; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_session_manager_memory.cpp b/src/lib/tls/tls_session_manager_memory.cpp new file mode 100644 index 000000000..24ede276c --- /dev/null +++ b/src/lib/tls/tls_session_manager_memory.cpp @@ -0,0 +1,122 @@ +/* +* TLS Session Management +* (C) 2011,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Session_Manager_In_Memory::Session_Manager_In_Memory( + RandomNumberGenerator& rng, + size_t max_sessions, + std::chrono::seconds session_lifetime) : + m_max_sessions(max_sessions), + m_session_lifetime(session_lifetime), + m_rng(rng), + m_session_key(m_rng, 32) + {} + +bool Session_Manager_In_Memory::load_from_session_str( + const std::string& session_str, Session& session) + { + // assert(lock is held) + + auto i = m_sessions.find(session_str); + + if(i == m_sessions.end()) + return false; + + try + { + session = Session::decrypt(i->second, m_session_key); + } + catch(...) + { + return false; + } + + // if session has expired, remove it + const auto now = std::chrono::system_clock::now(); + + if(session.start_time() + session_lifetime() < now) + { + m_sessions.erase(i); + return false; + } + + return true; + } + +bool Session_Manager_In_Memory::load_from_session_id( + const std::vector& session_id, Session& session) + { + std::lock_guard lock(m_mutex); + + return load_from_session_str(hex_encode(session_id), session); + } + +bool Session_Manager_In_Memory::load_from_server_info( + const Server_Information& info, Session& session) + { + std::lock_guard lock(m_mutex); + + auto i = m_info_sessions.find(info); + + if(i == m_info_sessions.end()) + return false; + + if(load_from_session_str(i->second, session)) + return true; + + /* + * It existed at one point but was removed from the sessions map, + * remove m_info_sessions entry as well + */ + m_info_sessions.erase(i); + + return false; + } + +void Session_Manager_In_Memory::remove_entry( + const std::vector& session_id) + { + std::lock_guard lock(m_mutex); + + auto i = m_sessions.find(hex_encode(session_id)); + + if(i != m_sessions.end()) + m_sessions.erase(i); + } + +void Session_Manager_In_Memory::save(const Session& session) + { + std::lock_guard lock(m_mutex); + + if(m_max_sessions != 0) + { + /* + We generate new session IDs with the first 4 bytes being a + timestamp, so this actually removes the oldest sessions first. + */ + while(m_sessions.size() >= m_max_sessions) + m_sessions.erase(m_sessions.begin()); + } + + const std::string session_id_str = hex_encode(session.session_id()); + + m_sessions[session_id_str] = session.encrypt(m_session_key, m_rng); + + if(session.side() == CLIENT && !session.server_info().empty()) + m_info_sessions[session.server_info()] = session_id_str; + } + +} + +} diff --git a/src/lib/tls/tls_suite_info.cpp b/src/lib/tls/tls_suite_info.cpp new file mode 100644 index 000000000..6d6e348e8 --- /dev/null +++ b/src/lib/tls/tls_suite_info.cpp @@ -0,0 +1,463 @@ +/* +* TLS cipher suite information +* +* This file was automatically generated from the IANA assignments +* (tls-parameters.txt hash a794db70c6546a47e3bc3181dc0fd908a322e50c) +* by ./src/scripts/tls_suite_info.py on 2014-01-07 +* +* Released under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace TLS { + +Ciphersuite Ciphersuite::by_id(u16bit suite) + { + switch(suite) + { + case 0x0013: // DHE_DSS_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0x0013, "DSA", "DH", "3DES", 24, 8, "SHA-1", 20); + + case 0x0032: // DHE_DSS_WITH_AES_128_CBC_SHA + return Ciphersuite(0x0032, "DSA", "DH", "AES-128", 16, 16, "SHA-1", 20); + + case 0x0040: // DHE_DSS_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0x0040, "DSA", "DH", "AES-128", 16, 16, "SHA-256", 32); + + case 0x00A2: // DHE_DSS_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0x00A2, "DSA", "DH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0038: // DHE_DSS_WITH_AES_256_CBC_SHA + return Ciphersuite(0x0038, "DSA", "DH", "AES-256", 32, 16, "SHA-1", 20); + + case 0x006A: // DHE_DSS_WITH_AES_256_CBC_SHA256 + return Ciphersuite(0x006A, "DSA", "DH", "AES-256", 32, 16, "SHA-256", 32); + + case 0x00A3: // DHE_DSS_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0x00A3, "DSA", "DH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0044: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite(0x0044, "DSA", "DH", "Camellia-128", 16, 16, "SHA-1", 20); + + case 0x00BD: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0x00BD, "DSA", "DH", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC080: // DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC080, "DSA", "DH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0087: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite(0x0087, "DSA", "DH", "Camellia-256", 32, 16, "SHA-1", 20); + + case 0x00C3: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite(0x00C3, "DSA", "DH", "Camellia-256", 32, 16, "SHA-256", 32); + + case 0xC081: // DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC081, "DSA", "DH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0066: // DHE_DSS_WITH_RC4_128_SHA + return Ciphersuite(0x0066, "DSA", "DH", "RC4", 16, 0, "SHA-1", 20); + + case 0x0099: // DHE_DSS_WITH_SEED_CBC_SHA + return Ciphersuite(0x0099, "DSA", "DH", "SEED", 16, 16, "SHA-1", 20); + + case 0x008F: // DHE_PSK_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0x008F, "", "DHE_PSK", "3DES", 24, 8, "SHA-1", 20); + + case 0x0090: // DHE_PSK_WITH_AES_128_CBC_SHA + return Ciphersuite(0x0090, "", "DHE_PSK", "AES-128", 16, 16, "SHA-1", 20); + + case 0x00B2: // DHE_PSK_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0x00B2, "", "DHE_PSK", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC0A6: // DHE_PSK_WITH_AES_128_CCM + return Ciphersuite(0xC0A6, "", "DHE_PSK", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x00AA: // DHE_PSK_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0x00AA, "", "DHE_PSK", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0091: // DHE_PSK_WITH_AES_256_CBC_SHA + return Ciphersuite(0x0091, "", "DHE_PSK", "AES-256", 32, 16, "SHA-1", 20); + + case 0x00B3: // DHE_PSK_WITH_AES_256_CBC_SHA384 + return Ciphersuite(0x00B3, "", "DHE_PSK", "AES-256", 32, 16, "SHA-384", 48); + + case 0xC0A7: // DHE_PSK_WITH_AES_256_CCM + return Ciphersuite(0xC0A7, "", "DHE_PSK", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); + + case 0x00AB: // DHE_PSK_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0x00AB, "", "DHE_PSK", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0xC096: // DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0xC096, "", "DHE_PSK", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC090: // DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC090, "", "DHE_PSK", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC097: // DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite(0xC097, "", "DHE_PSK", "Camellia-256", 32, 16, "SHA-384", 48); + + case 0xC091: // DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC091, "", "DHE_PSK", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x008E: // DHE_PSK_WITH_RC4_128_SHA + return Ciphersuite(0x008E, "", "DHE_PSK", "RC4", 16, 0, "SHA-1", 20); + + case 0x0016: // DHE_RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0x0016, "RSA", "DH", "3DES", 24, 8, "SHA-1", 20); + + case 0x0033: // DHE_RSA_WITH_AES_128_CBC_SHA + return Ciphersuite(0x0033, "RSA", "DH", "AES-128", 16, 16, "SHA-1", 20); + + case 0x0067: // DHE_RSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0x0067, "RSA", "DH", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC09E: // DHE_RSA_WITH_AES_128_CCM + return Ciphersuite(0xC09E, "RSA", "DH", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC0A2: // DHE_RSA_WITH_AES_128_CCM_8 + return Ciphersuite(0xC0A2, "RSA", "DH", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x009E: // DHE_RSA_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0x009E, "RSA", "DH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0039: // DHE_RSA_WITH_AES_256_CBC_SHA + return Ciphersuite(0x0039, "RSA", "DH", "AES-256", 32, 16, "SHA-1", 20); + + case 0x006B: // DHE_RSA_WITH_AES_256_CBC_SHA256 + return Ciphersuite(0x006B, "RSA", "DH", "AES-256", 32, 16, "SHA-256", 32); + + case 0xC09F: // DHE_RSA_WITH_AES_256_CCM + return Ciphersuite(0xC09F, "RSA", "DH", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); + + case 0xC0A3: // DHE_RSA_WITH_AES_256_CCM_8 + return Ciphersuite(0xC0A3, "RSA", "DH", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); + + case 0x009F: // DHE_RSA_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0x009F, "RSA", "DH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0045: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite(0x0045, "RSA", "DH", "Camellia-128", 16, 16, "SHA-1", 20); + + case 0x00BE: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0x00BE, "RSA", "DH", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC07C: // DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC07C, "RSA", "DH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0088: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite(0x0088, "RSA", "DH", "Camellia-256", 32, 16, "SHA-1", 20); + + case 0x00C4: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite(0x00C4, "RSA", "DH", "Camellia-256", 32, 16, "SHA-256", 32); + + case 0xC07D: // DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC07D, "RSA", "DH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x009A: // DHE_RSA_WITH_SEED_CBC_SHA + return Ciphersuite(0x009A, "RSA", "DH", "SEED", 16, 16, "SHA-1", 20); + + case 0x001B: // DH_anon_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0x001B, "", "DH", "3DES", 24, 8, "SHA-1", 20); + + case 0x0034: // DH_anon_WITH_AES_128_CBC_SHA + return Ciphersuite(0x0034, "", "DH", "AES-128", 16, 16, "SHA-1", 20); + + case 0x006C: // DH_anon_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0x006C, "", "DH", "AES-128", 16, 16, "SHA-256", 32); + + case 0x00A6: // DH_anon_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0x00A6, "", "DH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x003A: // DH_anon_WITH_AES_256_CBC_SHA + return Ciphersuite(0x003A, "", "DH", "AES-256", 32, 16, "SHA-1", 20); + + case 0x006D: // DH_anon_WITH_AES_256_CBC_SHA256 + return Ciphersuite(0x006D, "", "DH", "AES-256", 32, 16, "SHA-256", 32); + + case 0x00A7: // DH_anon_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0x00A7, "", "DH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0046: // DH_anon_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite(0x0046, "", "DH", "Camellia-128", 16, 16, "SHA-1", 20); + + case 0x00BF: // DH_anon_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0x00BF, "", "DH", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC084: // DH_anon_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC084, "", "DH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0089: // DH_anon_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite(0x0089, "", "DH", "Camellia-256", 32, 16, "SHA-1", 20); + + case 0x00C5: // DH_anon_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite(0x00C5, "", "DH", "Camellia-256", 32, 16, "SHA-256", 32); + + case 0xC085: // DH_anon_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC085, "", "DH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0018: // DH_anon_WITH_RC4_128_MD5 + return Ciphersuite(0x0018, "", "DH", "RC4", 16, 0, "MD5", 16); + + case 0x009B: // DH_anon_WITH_SEED_CBC_SHA + return Ciphersuite(0x009B, "", "DH", "SEED", 16, 16, "SHA-1", 20); + + case 0xC008: // ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC008, "ECDSA", "ECDH", "3DES", 24, 8, "SHA-1", 20); + + case 0xC009: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC009, "ECDSA", "ECDH", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC023: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0xC023, "ECDSA", "ECDH", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC02B: // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0xC02B, "ECDSA", "ECDH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC00A: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC00A, "ECDSA", "ECDH", "AES-256", 32, 16, "SHA-1", 20); + + case 0xC024: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + return Ciphersuite(0xC024, "ECDSA", "ECDH", "AES-256", 32, 16, "SHA-384", 48); + + case 0xC02C: // ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0xC02C, "ECDSA", "ECDH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0xC072: // ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0xC072, "ECDSA", "ECDH", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC086: // ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC086, "ECDSA", "ECDH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC073: // ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite(0xC073, "ECDSA", "ECDH", "Camellia-256", 32, 16, "SHA-384", 48); + + case 0xC087: // ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC087, "ECDSA", "ECDH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0xC007: // ECDHE_ECDSA_WITH_RC4_128_SHA + return Ciphersuite(0xC007, "ECDSA", "ECDH", "RC4", 16, 0, "SHA-1", 20); + + case 0xC034: // ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC034, "", "ECDHE_PSK", "3DES", 24, 8, "SHA-1", 20); + + case 0xC035: // ECDHE_PSK_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC035, "", "ECDHE_PSK", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC037: // ECDHE_PSK_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0xC037, "", "ECDHE_PSK", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC036: // ECDHE_PSK_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC036, "", "ECDHE_PSK", "AES-256", 32, 16, "SHA-1", 20); + + case 0xC038: // ECDHE_PSK_WITH_AES_256_CBC_SHA384 + return Ciphersuite(0xC038, "", "ECDHE_PSK", "AES-256", 32, 16, "SHA-384", 48); + + case 0xC09A: // ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0xC09A, "", "ECDHE_PSK", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC09B: // ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite(0xC09B, "", "ECDHE_PSK", "Camellia-256", 32, 16, "SHA-384", 48); + + case 0xC033: // ECDHE_PSK_WITH_RC4_128_SHA + return Ciphersuite(0xC033, "", "ECDHE_PSK", "RC4", 16, 0, "SHA-1", 20); + + case 0xC012: // ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC012, "RSA", "ECDH", "3DES", 24, 8, "SHA-1", 20); + + case 0xC013: // ECDHE_RSA_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC013, "RSA", "ECDH", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC027: // ECDHE_RSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0xC027, "RSA", "ECDH", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC02F: // ECDHE_RSA_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0xC02F, "RSA", "ECDH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC014: // ECDHE_RSA_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC014, "RSA", "ECDH", "AES-256", 32, 16, "SHA-1", 20); + + case 0xC028: // ECDHE_RSA_WITH_AES_256_CBC_SHA384 + return Ciphersuite(0xC028, "RSA", "ECDH", "AES-256", 32, 16, "SHA-384", 48); + + case 0xC030: // ECDHE_RSA_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0xC030, "RSA", "ECDH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0xC076: // ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0xC076, "RSA", "ECDH", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC08A: // ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC08A, "RSA", "ECDH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC077: // ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite(0xC077, "RSA", "ECDH", "Camellia-256", 32, 16, "SHA-384", 48); + + case 0xC08B: // ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC08B, "RSA", "ECDH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0xC011: // ECDHE_RSA_WITH_RC4_128_SHA + return Ciphersuite(0xC011, "RSA", "ECDH", "RC4", 16, 0, "SHA-1", 20); + + case 0xC017: // ECDH_anon_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC017, "", "ECDH", "3DES", 24, 8, "SHA-1", 20); + + case 0xC018: // ECDH_anon_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC018, "", "ECDH", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC019: // ECDH_anon_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC019, "", "ECDH", "AES-256", 32, 16, "SHA-1", 20); + + case 0xC016: // ECDH_anon_WITH_RC4_128_SHA + return Ciphersuite(0xC016, "", "ECDH", "RC4", 16, 0, "SHA-1", 20); + + case 0xC0AA: // PSK_DHE_WITH_AES_128_CCM_8 + return Ciphersuite(0xC0AA, "", "DHE_PSK", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC0AB: // PSK_DHE_WITH_AES_256_CCM_8 + return Ciphersuite(0xC0AB, "", "DHE_PSK", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); + + case 0x008B: // PSK_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0x008B, "", "PSK", "3DES", 24, 8, "SHA-1", 20); + + case 0x008C: // PSK_WITH_AES_128_CBC_SHA + return Ciphersuite(0x008C, "", "PSK", "AES-128", 16, 16, "SHA-1", 20); + + case 0x00AE: // PSK_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0x00AE, "", "PSK", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC0A4: // PSK_WITH_AES_128_CCM + return Ciphersuite(0xC0A4, "", "PSK", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC0A8: // PSK_WITH_AES_128_CCM_8 + return Ciphersuite(0xC0A8, "", "PSK", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x00A8: // PSK_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0x00A8, "", "PSK", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x008D: // PSK_WITH_AES_256_CBC_SHA + return Ciphersuite(0x008D, "", "PSK", "AES-256", 32, 16, "SHA-1", 20); + + case 0x00AF: // PSK_WITH_AES_256_CBC_SHA384 + return Ciphersuite(0x00AF, "", "PSK", "AES-256", 32, 16, "SHA-384", 48); + + case 0xC0A5: // PSK_WITH_AES_256_CCM + return Ciphersuite(0xC0A5, "", "PSK", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); + + case 0xC0A9: // PSK_WITH_AES_256_CCM_8 + return Ciphersuite(0xC0A9, "", "PSK", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); + + case 0x00A9: // PSK_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0x00A9, "", "PSK", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0xC094: // PSK_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0xC094, "", "PSK", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC08E: // PSK_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC08E, "", "PSK", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC095: // PSK_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite(0xC095, "", "PSK", "Camellia-256", 32, 16, "SHA-384", 48); + + case 0xC08F: // PSK_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC08F, "", "PSK", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x008A: // PSK_WITH_RC4_128_SHA + return Ciphersuite(0x008A, "", "PSK", "RC4", 16, 0, "SHA-1", 20); + + case 0x000A: // RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0x000A, "RSA", "RSA", "3DES", 24, 8, "SHA-1", 20); + + case 0x002F: // RSA_WITH_AES_128_CBC_SHA + return Ciphersuite(0x002F, "RSA", "RSA", "AES-128", 16, 16, "SHA-1", 20); + + case 0x003C: // RSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite(0x003C, "RSA", "RSA", "AES-128", 16, 16, "SHA-256", 32); + + case 0xC09C: // RSA_WITH_AES_128_CCM + return Ciphersuite(0xC09C, "RSA", "RSA", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0xC0A0: // RSA_WITH_AES_128_CCM_8 + return Ciphersuite(0xC0A0, "RSA", "RSA", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x009C: // RSA_WITH_AES_128_GCM_SHA256 + return Ciphersuite(0x009C, "RSA", "RSA", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0035: // RSA_WITH_AES_256_CBC_SHA + return Ciphersuite(0x0035, "RSA", "RSA", "AES-256", 32, 16, "SHA-1", 20); + + case 0x003D: // RSA_WITH_AES_256_CBC_SHA256 + return Ciphersuite(0x003D, "RSA", "RSA", "AES-256", 32, 16, "SHA-256", 32); + + case 0xC09D: // RSA_WITH_AES_256_CCM + return Ciphersuite(0xC09D, "RSA", "RSA", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); + + case 0xC0A1: // RSA_WITH_AES_256_CCM_8 + return Ciphersuite(0xC0A1, "RSA", "RSA", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); + + case 0x009D: // RSA_WITH_AES_256_GCM_SHA384 + return Ciphersuite(0x009D, "RSA", "RSA", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0041: // RSA_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite(0x0041, "RSA", "RSA", "Camellia-128", 16, 16, "SHA-1", 20); + + case 0x00BA: // RSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite(0x00BA, "RSA", "RSA", "Camellia-128", 16, 16, "SHA-256", 32); + + case 0xC07A: // RSA_WITH_CAMELLIA_128_GCM_SHA256 + return Ciphersuite(0xC07A, "RSA", "RSA", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); + + case 0x0084: // RSA_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite(0x0084, "RSA", "RSA", "Camellia-256", 32, 16, "SHA-1", 20); + + case 0x00C0: // RSA_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite(0x00C0, "RSA", "RSA", "Camellia-256", 32, 16, "SHA-256", 32); + + case 0xC07B: // RSA_WITH_CAMELLIA_256_GCM_SHA384 + return Ciphersuite(0xC07B, "RSA", "RSA", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); + + case 0x0004: // RSA_WITH_RC4_128_MD5 + return Ciphersuite(0x0004, "RSA", "RSA", "RC4", 16, 0, "MD5", 16); + + case 0x0005: // RSA_WITH_RC4_128_SHA + return Ciphersuite(0x0005, "RSA", "RSA", "RC4", 16, 0, "SHA-1", 20); + + case 0x0096: // RSA_WITH_SEED_CBC_SHA + return Ciphersuite(0x0096, "RSA", "RSA", "SEED", 16, 16, "SHA-1", 20); + + case 0xC01C: // SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC01C, "DSA", "SRP_SHA", "3DES", 24, 8, "SHA-1", 20); + + case 0xC01F: // SRP_SHA_DSS_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC01F, "DSA", "SRP_SHA", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC022: // SRP_SHA_DSS_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC022, "DSA", "SRP_SHA", "AES-256", 32, 16, "SHA-1", 20); + + case 0xC01B: // SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC01B, "RSA", "SRP_SHA", "3DES", 24, 8, "SHA-1", 20); + + case 0xC01E: // SRP_SHA_RSA_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC01E, "RSA", "SRP_SHA", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC021: // SRP_SHA_RSA_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC021, "RSA", "SRP_SHA", "AES-256", 32, 16, "SHA-1", 20); + + case 0xC01A: // SRP_SHA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite(0xC01A, "", "SRP_SHA", "3DES", 24, 8, "SHA-1", 20); + + case 0xC01D: // SRP_SHA_WITH_AES_128_CBC_SHA + return Ciphersuite(0xC01D, "", "SRP_SHA", "AES-128", 16, 16, "SHA-1", 20); + + case 0xC020: // SRP_SHA_WITH_AES_256_CBC_SHA + return Ciphersuite(0xC020, "", "SRP_SHA", "AES-256", 32, 16, "SHA-1", 20); + + } + + return Ciphersuite(); // some unknown ciphersuite + } + +} + +} diff --git a/src/lib/tls/tls_version.cpp b/src/lib/tls/tls_version.cpp new file mode 100644 index 000000000..7b880d98c --- /dev/null +++ b/src/lib/tls/tls_version.cpp @@ -0,0 +1,101 @@ +/* +* TLS Protocol Version Management +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +std::string Protocol_Version::to_string() const + { + const byte maj = major_version(); + const byte min = minor_version(); + + if(maj == 3 && min == 0) + return "SSL v3"; + + if(maj == 3 && min >= 1) // TLS v1.x + return "TLS v1." + std::to_string(min-1); + + if(maj == 254) // DTLS 1.x + return "DTLS v1." + std::to_string(255 - min); + + // Some very new or very old protocol (or bogus data) + return "Unknown " + std::to_string(maj) + "." + std::to_string(min); + } + +bool Protocol_Version::is_datagram_protocol() const + { + return major_version() == 254; + } + +bool Protocol_Version::operator>(const Protocol_Version& other) const + { + if(this->is_datagram_protocol() != other.is_datagram_protocol()) + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Version comparing " + to_string() + + " with " + other.to_string()); + + if(this->is_datagram_protocol()) + return m_version < other.m_version; // goes backwards + + return m_version > other.m_version; + } + +Protocol_Version Protocol_Version::best_known_match() const + { + if(known_version()) + return *this; // known version is its own best match + + if(is_datagram_protocol()) + return Protocol_Version::DTLS_V12; + else + return Protocol_Version::TLS_V12; + } + +bool Protocol_Version::known_version() const + { + return (m_version == Protocol_Version::SSL_V3 || + m_version == Protocol_Version::TLS_V10 || + m_version == Protocol_Version::TLS_V11 || + m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V10 || + m_version == Protocol_Version::DTLS_V12); + } + +bool Protocol_Version::supports_negotiable_signature_algorithms() const + { + return (m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V12); + } + +bool Protocol_Version::supports_explicit_cbc_ivs() const + { + return (m_version == Protocol_Version::TLS_V11 || + m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V10 || + m_version == Protocol_Version::DTLS_V12); + } + +bool Protocol_Version::supports_ciphersuite_specific_prf() const + { + return (m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V12); + } + +bool Protocol_Version::supports_aead_modes() const + { + return (m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V12); + } + +} + +} diff --git a/src/lib/tls/tls_version.h b/src/lib/tls/tls_version.h new file mode 100644 index 000000000..9fd71b629 --- /dev/null +++ b/src/lib/tls/tls_version.h @@ -0,0 +1,151 @@ +/* +* TLS Protocol Version Management +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_PROTOCOL_VERSION_H__ +#define BOTAN_TLS_PROTOCOL_VERSION_H__ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Protocol Version +*/ +class BOTAN_DLL Protocol_Version + { + public: + enum Version_Code { + SSL_V3 = 0x0300, + TLS_V10 = 0x0301, + TLS_V11 = 0x0302, + TLS_V12 = 0x0303, + + DTLS_V10 = 0xFEFF, + DTLS_V12 = 0xFEFD + }; + + static Protocol_Version latest_tls_version() + { + return Protocol_Version(TLS_V12); + } + + static Protocol_Version latest_dtls_version() + { + return Protocol_Version(DTLS_V12); + } + + Protocol_Version() : m_version(0) {} + + /** + * @param named_version a specific named version of the protocol + */ + Protocol_Version(Version_Code named_version) : + m_version(static_cast(named_version)) {} + + /** + * @param major the major version + * @param minor the minor version + */ + Protocol_Version(byte major, byte minor) : + m_version((static_cast(major) << 8) | minor) {} + + /** + * @return true if this is a valid protocol version + */ + bool valid() const { return (m_version != 0); } + + /** + * @return true if this is a protocol version we know about + */ + bool known_version() const; + + /** + * @return major version of the protocol version + */ + byte major_version() const { return get_byte(0, m_version); } + + /** + * @return minor version of the protocol version + */ + byte minor_version() const { return get_byte(1, m_version); } + + /** + * @return human-readable description of this version + */ + std::string to_string() const; + + /** + * If this version is known, return that. Otherwise return the + * best (most recent) version we know of. + * @return best matching protocol version + */ + Protocol_Version best_known_match() const; + + /** + * @return true iff this is a DTLS version + */ + bool is_datagram_protocol() const; + + /** + * @return true if this version supports negotiable signature algorithms + */ + bool supports_negotiable_signature_algorithms() const; + + /** + * @return true if this version uses explicit IVs for block ciphers + */ + bool supports_explicit_cbc_ivs() const; + + /** + * @return true if this version uses a ciphersuite specific PRF + */ + bool supports_ciphersuite_specific_prf() const; + + bool supports_aead_modes() const; + + /** + * @return if this version is equal to other + */ + bool operator==(const Protocol_Version& other) const + { + return (m_version == other.m_version); + } + + /** + * @return if this version is not equal to other + */ + bool operator!=(const Protocol_Version& other) const + { + return (m_version != other.m_version); + } + + /** + * @return if this version is later than other + */ + bool operator>(const Protocol_Version& other) const; + + /** + * @return if this version is later than or equal to other + */ + bool operator>=(const Protocol_Version& other) const + { + return (*this == other || *this > other); + } + + private: + u16bit m_version; + }; + +} + +} + +#endif + diff --git a/src/lib/utils/asm_x86_32/asm_x86_32.h b/src/lib/utils/asm_x86_32/asm_x86_32.h new file mode 100644 index 000000000..d5482c419 --- /dev/null +++ b/src/lib/utils/asm_x86_32/asm_x86_32.h @@ -0,0 +1,128 @@ +/* +* Assembly Macros for 32-bit x86 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASM_MACROS_X86_32_H__ +#define BOTAN_ASM_MACROS_X86_32_H__ + +/* +* General/Global Macros +*/ +#define ALIGN .p2align 4,,15 + +#define START_LISTING(FILENAME) \ + .file #FILENAME; \ + .text; \ + ALIGN; + +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +/* +* Function Definitions +*/ +#define START_FUNCTION(func_name) \ + ALIGN; \ + .global func_name; \ + .type func_name,@function; \ +func_name: + +#define END_FUNCTION(func_name) \ + ret + +/* +* Loop Control +*/ +#define START_LOOP(LABEL) \ + ALIGN; \ + LABEL##_LOOP: + +#define LOOP_UNTIL_EQ(REG, NUM, LABEL) \ + cmpl IMM(NUM), REG; \ + jne LABEL##_LOOP + +#define LOOP_UNTIL_LT(REG, NUM, LABEL) \ + cmpl IMM(NUM), REG; \ + jge LABEL##_LOOP + +/* + Conditional Jumps +*/ +#define JUMP_IF_ZERO(REG, LABEL) \ + cmpl IMM(0), REG; \ + jz LABEL + +#define JUMP_IF_LT(REG, NUM, LABEL) \ + cmpl IMM(NUM), REG; \ + jl LABEL + +/* +* Register Names +*/ +#define EAX %eax +#define EBX %ebx +#define ECX %ecx +#define EDX %edx +#define EBP %ebp +#define EDI %edi +#define ESI %esi +#define ESP %esp + +/* +* Memory Access Operations +*/ +#define ARRAY1(REG, NUM) (NUM)(REG) +#define ARRAY4(REG, NUM) 4*(NUM)(REG) +#define ARRAY4_INDIRECT(BASE, OFFSET, NUM) 4*(NUM)(BASE,OFFSET,4) +#define ARG(NUM) 4*(PUSHED) + ARRAY4(ESP, NUM) + +#define ASSIGN(TO, FROM) movl FROM, TO +#define ASSIGN_BYTE(TO, FROM) movzbl FROM, TO + +#define PUSH(REG) pushl REG +#define POP(REG) popl REG + +#define SPILL_REGS() \ + PUSH(EBP) ; \ + PUSH(EDI) ; \ + PUSH(ESI) ; \ + PUSH(EBX) + +#define RESTORE_REGS() \ + POP(EBX) ; \ + POP(ESI) ; \ + POP(EDI) ; \ + POP(EBP) + +/* +* ALU Operations +*/ +#define IMM(VAL) $VAL + +#define ADD(TO, FROM) addl FROM, TO +#define ADD_IMM(TO, NUM) ADD(TO, IMM(NUM)) +#define ADD_W_CARRY(TO1, TO2, FROM) addl FROM, TO1; adcl IMM(0), TO2; +#define SUB_IMM(TO, NUM) subl IMM(NUM), TO +#define ADD2_IMM(TO, FROM, NUM) leal NUM(FROM), TO +#define ADD3_IMM(TO, FROM, NUM) leal NUM(TO,FROM,1), TO +#define MUL(REG) mull REG + +#define SHL_IMM(REG, SHIFT) shll IMM(SHIFT), REG +#define SHR_IMM(REG, SHIFT) shrl IMM(SHIFT), REG +#define SHL2_3(TO, FROM) leal 0(,FROM,8), TO + +#define XOR(TO, FROM) xorl FROM, TO +#define AND(TO, FROM) andl FROM, TO +#define OR(TO, FROM) orl FROM, TO +#define NOT(REG) notl REG +#define ZEROIZE(REG) XOR(REG, REG) + +#define ROTL_IMM(REG, NUM) roll IMM(NUM), REG +#define ROTR_IMM(REG, NUM) rorl IMM(NUM), REG +#define BSWAP(REG) bswapl REG + +#endif diff --git a/src/lib/utils/asm_x86_32/info.txt b/src/lib/utils/asm_x86_32/info.txt new file mode 100644 index 000000000..d29b25fa3 --- /dev/null +++ b/src/lib/utils/asm_x86_32/info.txt @@ -0,0 +1,29 @@ +load_on dep + + +asm_x86_32.h + + + +x86_32 + + +# ELF systems + +linux +freebsd +dragonfly +netbsd +openbsd +solaris + + + +gcc +clang +icc + + + +asm_engine + diff --git a/src/lib/utils/asm_x86_64/asm_x86_64.h b/src/lib/utils/asm_x86_64/asm_x86_64.h new file mode 100644 index 000000000..7abc1f392 --- /dev/null +++ b/src/lib/utils/asm_x86_64/asm_x86_64.h @@ -0,0 +1,127 @@ +/* +* Assembly Macros for 64-bit x86 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASM_MACROS_X86_64_H__ +#define BOTAN_ASM_MACROS_X86_64_H__ + +/* +* General/Global Macros +*/ +#define ALIGN .p2align 4,,15 + +#define START_LISTING(FILENAME) \ + .file #FILENAME; \ + .text; \ + ALIGN; + +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +/* +* Function Definitions +*/ +#define START_FUNCTION(func_name) \ + ALIGN; \ + .global func_name; \ + .type func_name,@function; \ +func_name: + +#define END_FUNCTION(func_name) \ + ret + +/* +* Conditional Jumps +*/ +#define JUMP_IF_ZERO(REG, LABEL) \ + cmp IMM(0), REG; \ + jz LABEL + +#define JUMP_IF_LT(REG, NUM, LABEL) \ + cmp IMM(NUM), REG; \ + jl LABEL + +/* +* Register Names +*/ +#define R0 %rax +#define R1 %rbx +#define R2 %rcx +#define R2_32 %ecx +#define R3 %rdx +#define R3_32 %edx +#define R4 %rsp +#define R5 %rbp +#define R6 %rsi +#define R6_32 %esi +#define R7 %rdi +#define R8 %r8 +#define R9 %r9 +#define R9_32 %r9d +#define R10 %r10 +#define R11 %r11 +#define R12 %r12 +#define R13 %r13 +#define R14 %r14 +#define R15 %r15 +#define R16 %r16 + +#define ARG_1 R7 +#define ARG_2 R6 +#define ARG_2_32 R6_32 +#define ARG_3 R3 +#define ARG_3_32 R3_32 +#define ARG_4 R2 +#define ARG_4_32 R2_32 +#define ARG_5 R8 +#define ARG_6 R9 +#define ARG_6_32 R9_32 + +#define TEMP_1 R10 +#define TEMP_2 R11 +#define TEMP_3 ARG_6 +#define TEMP_4 ARG_5 +#define TEMP_5 ARG_4 +#define TEMP_5_32 ARG_4_32 +#define TEMP_6 ARG_3 +#define TEMP_7 ARG_2 +#define TEMP_8 ARG_1 +#define TEMP_9 R0 + +/* +* Memory Access Operations +*/ +#define ARRAY8(REG, NUM) 8*(NUM)(REG) +#define ARRAY4(REG, NUM) 4*(NUM)(REG) + +#define ASSIGN(TO, FROM) mov FROM, TO + +/* +* ALU Operations +*/ +#define IMM(VAL) $VAL + +#define ADD(TO, FROM) add FROM, TO +#define ADD_LAST_CARRY(REG) adc IMM(0), REG +#define ADD_IMM(TO, NUM) ADD(TO, IMM(NUM)) +#define ADD_W_CARRY(TO1, TO2, FROM) add FROM, TO1; adc IMM(0), TO2; +#define SUB_IMM(TO, NUM) sub IMM(NUM), TO +#define MUL(REG) mul REG + +#define XOR(TO, FROM) xor FROM, TO +#define AND(TO, FROM) and FROM, TO +#define OR(TO, FROM) or FROM, TO +#define NOT(REG) not REG +#define ZEROIZE(REG) XOR(REG, REG) + +#define RETURN_VALUE_IS(V) ASSIGN(%rax, V) + +#define ROTL_IMM(REG, NUM) rol IMM(NUM), REG +#define ROTR_IMM(REG, NUM) ror IMM(NUM), REG +#define ADD3_IMM(TO, FROM, NUM) lea NUM(TO,FROM,1), TO + +#endif diff --git a/src/lib/utils/asm_x86_64/info.txt b/src/lib/utils/asm_x86_64/info.txt new file mode 100644 index 000000000..3173f3b14 --- /dev/null +++ b/src/lib/utils/asm_x86_64/info.txt @@ -0,0 +1,27 @@ +load_on dep + + +asm_x86_64.h + + + +x86_64 + + + +clang +gcc +icc + + +# ELF systems + +linux +netbsd +openbsd +solaris + + + +asm_engine + diff --git a/src/lib/utils/assert.cpp b/src/lib/utils/assert.cpp new file mode 100644 index 000000000..b6d4f4240 --- /dev/null +++ b/src/lib/utils/assert.cpp @@ -0,0 +1,36 @@ +/* +* Runtime assertion checking +* (C) 2010,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +void assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line) + { + std::ostringstream format; + + format << "False assertion "; + + if(assertion_made && assertion_made[0] != 0) + format << "'" << assertion_made << "' (expression " << expr_str << ") "; + else + format << expr_str << " "; + + if(func) + format << "in " << func << " "; + + format << "@" << file << ":" << line; + + throw std::runtime_error(format.str()); + } + +} diff --git a/src/lib/utils/assert.h b/src/lib/utils/assert.h new file mode 100644 index 000000000..f62fae63e --- /dev/null +++ b/src/lib/utils/assert.h @@ -0,0 +1,83 @@ +/* +* Runtime assertion checking +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASSERTION_CHECKING_H__ +#define BOTAN_ASSERTION_CHECKING_H__ + +#include + +namespace Botan { + +/** +* Called when an assertion fails +*/ +void BOTAN_DLL assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line); + +/** +* Make an assertion +*/ +#define BOTAN_ASSERT(expr, assertion_made) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + assertion_made, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that value1 == value2 +*/ +#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made) \ + do { \ + if((expr1) != (expr2)) \ + Botan::assertion_failure(#expr1 " == " #expr2, \ + assertion_made, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that expr1 (if true) implies expr2 is also true +*/ +#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg) \ + do { \ + if((expr1) && !(expr2)) \ + Botan::assertion_failure(#expr1 " implies " #expr2, \ + msg, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that a pointer is not null +*/ +#define BOTAN_ASSERT_NONNULL(ptr) \ + do { \ + if(static_cast(ptr) == false) \ + Botan::assertion_failure(#ptr " is not null", \ + "", \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Mark variable as unused +*/ +#define BOTAN_UNUSED(v) static_cast(v) + +} + +#endif diff --git a/src/lib/utils/bit_ops.h b/src/lib/utils/bit_ops.h new file mode 100644 index 000000000..0072fde71 --- /dev/null +++ b/src/lib/utils/bit_ops.h @@ -0,0 +1,103 @@ +/* +* Bit/Word Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BIT_OPS_H__ +#define BOTAN_BIT_OPS_H__ + +#include + +namespace Botan { + +/** +* Power of 2 test. T should be an unsigned integer type +* @param arg an integer value +* @return true iff arg is 2^n for some n > 0 +*/ +template +inline bool is_power_of_2(T arg) + { + return ((arg != 0 && arg != 1) && ((arg & (arg-1)) == 0)); + } + +/** +* Return the index of the highest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the highest set bit in n +*/ +template +inline size_t high_bit(T n) + { + for(size_t i = 8*sizeof(T); i > 0; --i) + if((n >> (i - 1)) & 0x01) + return i; + return 0; + } + +/** +* Return the index of the lowest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the lowest set bit in n +*/ +template +inline size_t low_bit(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return (i + 1); + return 0; + } + +/** +* Return the number of significant bytes in n +* @param n an integer value +* @return number of significant bytes in n +*/ +template +inline size_t significant_bytes(T n) + { + for(size_t i = 0; i != sizeof(T); ++i) + if(get_byte(i, n)) + return sizeof(T)-i; + return 0; + } + +/** +* Compute Hamming weights +* @param n an integer value +* @return number of bits in n set to 1 +*/ +template +inline size_t hamming_weight(T n) + { + const byte NIBBLE_WEIGHTS[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + + size_t weight = 0; + for(size_t i = 0; i != 2*sizeof(T); ++i) + weight += NIBBLE_WEIGHTS[(n >> (4*i)) & 0x0F]; + return weight; + } + +/** +* Count the trailing zero bits in n +* @param n an integer value +* @return maximum x st 2^x divides n +*/ +template +inline size_t ctz(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return i; + return 8*sizeof(T); + } + +} + +#endif diff --git a/src/lib/utils/boost/info.txt b/src/lib/utils/boost/info.txt new file mode 100644 index 000000000..e87fd5b88 --- /dev/null +++ b/src/lib/utils/boost/info.txt @@ -0,0 +1,7 @@ +define BOOST_FILESYSTEM 20131228 +define BOOST_ASIO 20131228 + + +all -> boost_system,boost_filesystem + + diff --git a/src/lib/utils/bswap.h b/src/lib/utils/bswap.h new file mode 100644 index 000000000..9d2c9bc28 --- /dev/null +++ b/src/lib/utils/bswap.h @@ -0,0 +1,142 @@ +/* +* Byte Swapping Operations +* (C) 1999-2011 Jack Lloyd +* (C) 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BYTE_SWAP_H__ +#define BOTAN_BYTE_SWAP_H__ + +#include +#include + +#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) + #include +#endif + +namespace Botan { + +/** +* Swap a 16 bit integer +*/ +inline u16bit reverse_bytes(u16bit val) + { + return rotate_left(val, 8); + } + +/** +* Swap a 32 bit integer +*/ +inline u32bit reverse_bytes(u32bit val) + { +#if BOTAN_GCC_VERSION >= 430 && !defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + /* + GCC intrinsic added in 4.3, works for a number of CPUs + + However avoid under ARM, as it branches to a function in libgcc + instead of generating inline asm, so slower even than the generic + rotate version below. + */ + return __builtin_bswap32(val); + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + // GCC-style inline assembly for x86 or x86-64 + asm("bswapl %0" : "=r" (val) : "0" (val)); + return val; + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + + asm ("eor r3, %1, %1, ror #16\n\t" + "bic r3, r3, #0x00FF0000\n\t" + "mov %0, %1, ror #8\n\t" + "eor %0, %0, r3, lsr #8" + : "=r" (val) + : "0" (val) + : "r3", "cc"); + + return val; + +#elif defined(_MSC_VER) && defined(BOTAN_TARGET_ARCH_IS_X86_32) + + // Visual C++ inline asm for 32-bit x86, by Yves Jerschow + __asm mov eax, val; + __asm bswap eax; + +#else + + // Generic implementation + return (rotate_right(val, 8) & 0xFF00FF00) | + (rotate_left (val, 8) & 0x00FF00FF); + +#endif + } + +/** +* Swap a 64 bit integer +*/ +inline u64bit reverse_bytes(u64bit val) + { +#if BOTAN_GCC_VERSION >= 430 + + // GCC intrinsic added in 4.3, works for a number of CPUs + return __builtin_bswap64(val); + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_ARCH_IS_X86_64) + // GCC-style inline assembly for x86-64 + asm("bswapq %0" : "=r" (val) : "0" (val)); + return val; + +#else + /* Generic implementation. Defined in terms of 32-bit bswap so any + * optimizations in that version can help here (particularly + * useful for 32-bit x86). + */ + + u32bit hi = static_cast(val >> 32); + u32bit lo = static_cast(val); + + hi = reverse_bytes(hi); + lo = reverse_bytes(lo); + + return (static_cast(lo) << 32) | hi; +#endif + } + +/** +* Swap 4 Ts in an array +*/ +template +inline void bswap_4(T x[4]) + { + x[0] = reverse_bytes(x[0]); + x[1] = reverse_bytes(x[1]); + x[2] = reverse_bytes(x[2]); + x[3] = reverse_bytes(x[3]); + } + +#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) + +/** +* Swap 4 u32bits in an array using SSE2 shuffle instructions +*/ +template<> +inline void bswap_4(u32bit x[4]) + { + __m128i T = _mm_loadu_si128(reinterpret_cast(x)); + + T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + + T = _mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(x), T); + } + +#endif + +} + +#endif diff --git a/src/lib/utils/calendar.cpp b/src/lib/utils/calendar.cpp new file mode 100644 index 000000000..14f0113f2 --- /dev/null +++ b/src/lib/utils/calendar.cpp @@ -0,0 +1,52 @@ +/* +* Calendar Functions +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +std::tm do_gmtime(std::time_t time_val) + { + std::tm tm; + +#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S) + gmtime_s(&tm, &time_val); // Windows +#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R) + gmtime_r(&time_val, &tm); // Unix/SUSv2 +#else + std::tm* tm_p = std::gmtime(&time_val); + if (tm_p == 0) + throw Encoding_Error("time_t_to_tm could not convert"); + tm = *tm_p; +#endif + + return tm; + } + +} + +/* +* Convert a time_point to a calendar_point +*/ +calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point) + { + std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point)); + + return calendar_point(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); + } + +} diff --git a/src/lib/utils/calendar.h b/src/lib/utils/calendar.h new file mode 100644 index 000000000..d617cc9a0 --- /dev/null +++ b/src/lib/utils/calendar.h @@ -0,0 +1,63 @@ +/* +* Calendar Functions +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CALENDAR_H__ +#define BOTAN_CALENDAR_H__ + +#include +#include + +namespace Botan { + +/** +* Struct representing a particular date and time +*/ +struct BOTAN_DLL calendar_point + { + /** The year */ + u32bit year; + + /** The month, 1 through 12 for Jan to Dec */ + byte month; + + /** The day of the month, 1 through 31 (or 28 or 30 based on month */ + byte day; + + /** Hour in 24-hour form, 0 to 23 */ + byte hour; + + /** Minutes in the hour, 0 to 60 */ + byte minutes; + + /** Seconds in the minute, 0 to 60, but might be slightly + larger to deal with leap seconds on some systems + */ + byte seconds; + + /** + * Initialize a calendar_point + * @param y the year + * @param mon the month + * @param d the day + * @param h the hour + * @param min the minute + * @param sec the second + */ + calendar_point(u32bit y, byte mon, byte d, byte h, byte min, byte sec) : + year(y), month(mon), day(d), hour(h), minutes(min), seconds(sec) {} + }; + +/* +* @param time_point a time point from the system clock +* @return calendar_point object representing this time point +*/ +BOTAN_DLL calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point); + +} + +#endif diff --git a/src/lib/utils/charset.cpp b/src/lib/utils/charset.cpp new file mode 100644 index 000000000..7ee637f80 --- /dev/null +++ b/src/lib/utils/charset.cpp @@ -0,0 +1,201 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace Charset { + +namespace { + +/* +* Convert from UCS-2 to ISO 8859-1 +*/ +std::string ucs2_to_latin1(const std::string& ucs2) + { + if(ucs2.size() % 2 == 1) + throw Decoding_Error("UCS-2 string has an odd number of bytes"); + + std::string latin1; + + for(size_t i = 0; i != ucs2.size(); i += 2) + { + const byte c1 = ucs2[i]; + const byte c2 = ucs2[i+1]; + + if(c1 != 0) + throw Decoding_Error("UCS-2 has non-Latin1 characters"); + + latin1 += static_cast(c2); + } + + return latin1; + } + +/* +* Convert from UTF-8 to ISO 8859-1 +*/ +std::string utf8_to_latin1(const std::string& utf8) + { + std::string iso8859; + + size_t position = 0; + while(position != utf8.size()) + { + const byte c1 = static_cast(utf8[position++]); + + if(c1 <= 0x7F) + iso8859 += static_cast(c1); + else if(c1 >= 0xC0 && c1 <= 0xC7) + { + if(position == utf8.size()) + throw Decoding_Error("UTF-8: sequence truncated"); + + const byte c2 = static_cast(utf8[position++]); + const byte iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F); + + if(iso_char <= 0x7F) + throw Decoding_Error("UTF-8: sequence longer than needed"); + + iso8859 += static_cast(iso_char); + } + else + throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used"); + } + + return iso8859; + } + +/* +* Convert from ISO 8859-1 to UTF-8 +*/ +std::string latin1_to_utf8(const std::string& iso8859) + { + std::string utf8; + for(size_t i = 0; i != iso8859.size(); ++i) + { + const byte c = static_cast(iso8859[i]); + + if(c <= 0x7F) + utf8 += static_cast(c); + else + { + utf8 += static_cast((0xC0 | (c >> 6))); + utf8 += static_cast((0x80 | (c & 0x3F))); + } + } + return utf8; + } + +} + +/* +* Perform character set transcoding +*/ +std::string transcode(const std::string& str, + Character_Set to, Character_Set from) + { + if(to == LOCAL_CHARSET) + to = LATIN1_CHARSET; + if(from == LOCAL_CHARSET) + from = LATIN1_CHARSET; + + if(to == from) + return str; + + if(from == LATIN1_CHARSET && to == UTF8_CHARSET) + return latin1_to_utf8(str); + if(from == UTF8_CHARSET && to == LATIN1_CHARSET) + return utf8_to_latin1(str); + if(from == UCS2_CHARSET && to == LATIN1_CHARSET) + return ucs2_to_latin1(str); + + throw Invalid_Argument("Unknown transcoding operation from " + + std::to_string(from) + " to " + std::to_string(to)); + } + +/* +* Check if a character represents a digit +*/ +bool is_digit(char c) + { + if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9') + return true; + return false; + } + +/* +* Check if a character represents whitespace +*/ +bool is_space(char c) + { + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + return true; + return false; + } + +/* +* Convert a character to a digit +*/ +byte char2digit(char c) + { + switch(c) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + + throw Invalid_Argument("char2digit: Input is not a digit character"); + } + +/* +* Convert a digit to a character +*/ +char digit2char(byte b) + { + switch(b) + { + case 0: return '0'; + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + case 8: return '8'; + case 9: return '9'; + } + + throw Invalid_Argument("digit2char: Input is not a digit"); + } + +/* +* Case-insensitive character comparison +*/ +bool caseless_cmp(char a, char b) + { + return (std::tolower(static_cast(a)) == + std::tolower(static_cast(b))); + } + +} + +} diff --git a/src/lib/utils/charset.h b/src/lib/utils/charset.h new file mode 100644 index 000000000..afb11733b --- /dev/null +++ b/src/lib/utils/charset.h @@ -0,0 +1,46 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CHARSET_H__ +#define BOTAN_CHARSET_H__ + +#include +#include + +namespace Botan { + +/** +* The different charsets (nominally) supported by Botan. +*/ +enum Character_Set { + LOCAL_CHARSET, + UCS2_CHARSET, + UTF8_CHARSET, + LATIN1_CHARSET +}; + +namespace Charset { + +/* +* Character Set Handling +*/ +std::string BOTAN_DLL transcode(const std::string& str, + Character_Set to, + Character_Set from); + +bool BOTAN_DLL is_digit(char c); +bool BOTAN_DLL is_space(char c); +bool BOTAN_DLL caseless_cmp(char x, char y); + +byte BOTAN_DLL char2digit(char c); +char BOTAN_DLL digit2char(byte b); + +} + +} + +#endif diff --git a/src/lib/utils/cpuid.cpp b/src/lib/utils/cpuid.cpp new file mode 100644 index 000000000..6da5673c1 --- /dev/null +++ b/src/lib/utils/cpuid.cpp @@ -0,0 +1,236 @@ +/* +* Runtime CPU detection +* (C) 2009-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +#if defined(BOTAN_TARGET_OS_IS_DARWIN) + #include +#endif + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + #include + #include + #include +#endif + +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + +#include + +#define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) +#define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + +#include + +#define X86_CPUID(type, out) do { __cpuid(out, type); } while(0) +#define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && BOTAN_USE_GCC_INLINE_ASM + +#define X86_CPUID(type, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type)) + +#define X86_CPUID_SUBLEVEL(type, level, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type), "2" (level)) + +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) + +#include + +#define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0) + +#define X86_CPUID_SUBLEVEL(type, level, out) \ + do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0) + +#else + +#warning "No way of calling cpuid for this compiler" + +#define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0) +#define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0) + +#endif + +#endif + +namespace Botan { + +u64bit CPUID::m_x86_processor_flags[2] = { 0, 0 }; +size_t CPUID::m_cache_line_size = 0; +bool CPUID::m_altivec_capable = false; + +namespace { + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +bool altivec_check_sysctl() + { +#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD) + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + int sels[2] = { CTL_MACHDEP, CPU_ALTIVEC }; +#else + // From Apple's docs + int sels[2] = { CTL_HW, HW_VECTORUNIT }; +#endif + int vector_type = 0; + size_t length = sizeof(vector_type); + int error = sysctl(sels, 2, &vector_type, &length, NULL, 0); + + if(error == 0 && vector_type > 0) + return true; +#endif + + return false; + } + +bool altivec_check_pvr_emul() + { + bool altivec_capable = false; + +#if defined(BOTAN_TARGET_OS_IS_LINUX) || defined(BOTAN_TARGET_OS_IS_NETBSD) + + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + Normally it is only accessible to ring 0, but Linux and NetBSD + (others, too, maybe?) will trap and emulate it for us. + + PVR identifiers for various AltiVec enabled CPUs. Taken from + PearPC and Linux sources, mostly. + */ + + const u16bit PVR_G4_7400 = 0x000C; + const u16bit PVR_G5_970 = 0x0039; + const u16bit PVR_G5_970FX = 0x003C; + const u16bit PVR_G5_970MP = 0x0044; + const u16bit PVR_G5_970GX = 0x0045; + const u16bit PVR_POWER6 = 0x003E; + const u16bit PVR_POWER7 = 0x003F; + const u16bit PVR_CELL_PPU = 0x0070; + + // Motorola produced G4s with PVR 0x800[0123C] (at least) + const u16bit PVR_G4_74xx_24 = 0x800; + + u32bit pvr = 0; + + asm volatile("mfspr %0, 287" : "=r" (pvr)); + + // Top 16 bit suffice to identify model + pvr >>= 16; + + altivec_capable |= (pvr == PVR_G4_7400); + altivec_capable |= ((pvr >> 4) == PVR_G4_74xx_24); + altivec_capable |= (pvr == PVR_G5_970); + altivec_capable |= (pvr == PVR_G5_970FX); + altivec_capable |= (pvr == PVR_G5_970MP); + altivec_capable |= (pvr == PVR_G5_970GX); + altivec_capable |= (pvr == PVR_POWER6); + altivec_capable |= (pvr == PVR_POWER7); + altivec_capable |= (pvr == PVR_CELL_PPU); +#endif + + return altivec_capable; + } + +#endif + +} + +void CPUID::print(std::ostream& o) + { + o << "CPUID flags: "; + +#define CPUID_PRINT(flag) do { if(has_##flag()) o << #flag << " "; } while(0) + CPUID_PRINT(sse2); + CPUID_PRINT(ssse3); + CPUID_PRINT(sse41); + CPUID_PRINT(sse42); + CPUID_PRINT(avx2); + CPUID_PRINT(avx512f); + CPUID_PRINT(altivec); + + CPUID_PRINT(rdtsc); + CPUID_PRINT(bmi2); + CPUID_PRINT(clmul); + CPUID_PRINT(aes_ni); + CPUID_PRINT(rdrand); + CPUID_PRINT(rdseed); + CPUID_PRINT(intel_sha); + CPUID_PRINT(adx); +#undef CPUID_PRINT + o << "\n"; + } + +void CPUID::initialize() + { +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + if(altivec_check_sysctl() || altivec_check_pvr_emul()) + altivec_capable = true; +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + const u32bit INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 }; + const u32bit AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 }; + + u32bit cpuid[4] = { 0 }; + X86_CPUID(0, cpuid); + + const u32bit max_supported_sublevel = cpuid[0]; + + if(max_supported_sublevel == 0) + return; + + const bool is_intel = same_mem(cpuid + 1, INTEL_CPUID, 3); + const bool is_amd = same_mem(cpuid + 1, AMD_CPUID, 3); + + X86_CPUID(1, cpuid); + + m_x86_processor_flags[0] = (static_cast(cpuid[2]) << 32) | cpuid[3]; + + if(is_intel) + m_cache_line_size = 8 * get_byte(2, cpuid[1]); + + if(max_supported_sublevel >= 7) + { + clear_mem(cpuid, 4); + X86_CPUID_SUBLEVEL(7, 0, cpuid); + m_x86_processor_flags[1] = (static_cast(cpuid[2]) << 32) | cpuid[1]; + } + + if(is_amd) + { + X86_CPUID(0x80000005, cpuid); + m_cache_line_size = get_byte(3, cpuid[2]); + } + +#endif + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + /* + * If we don't have access to CPUID, we can still safely assume that + * any x86-64 processor has SSE2 and RDTSC + */ + if(m_x86_processor_flags[0] == 0) + m_x86_processor_flags[0] = (1 << CPUID_SSE2_BIT) | (1 << CPUID_RDTSC_BIT); +#endif + } + +} diff --git a/src/lib/utils/cpuid.h b/src/lib/utils/cpuid.h new file mode 100644 index 000000000..1c4c1df0b --- /dev/null +++ b/src/lib/utils/cpuid.h @@ -0,0 +1,153 @@ +/* +* Runtime CPU detection +* (C) 2009-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CPUID_H__ +#define BOTAN_CPUID_H__ + +#include +#include + +namespace Botan { + +/** +* A class handling runtime CPU feature detection +*/ +class BOTAN_DLL CPUID + { + public: + /** + * Probe the CPU and see what extensions are supported + */ + static void initialize(); + + /** + * Return a best guess of the cache line size + */ + static size_t cache_line_size() { return m_cache_line_size; } + + /** + * Check if the processor supports RDTSC + */ + static bool has_rdtsc() + { return x86_processor_flags_has(CPUID_RDTSC_BIT); } + + /** + * Check if the processor supports SSE2 + */ + static bool has_sse2() + { return x86_processor_flags_has(CPUID_SSE2_BIT); } + + /** + * Check if the processor supports SSSE3 + */ + static bool has_ssse3() + { return x86_processor_flags_has(CPUID_SSSE3_BIT); } + + /** + * Check if the processor supports SSE4.1 + */ + static bool has_sse41() + { return x86_processor_flags_has(CPUID_SSE41_BIT); } + + /** + * Check if the processor supports SSE4.2 + */ + static bool has_sse42() + { return x86_processor_flags_has(CPUID_SSE42_BIT); } + + /** + * Check if the processor supports AVX2 + */ + static bool has_avx2() + { return x86_processor_flags_has(CPUID_AVX2_BIT); } + + /** + * Check if the processor supports AVX-512F + */ + static bool has_avx512f() + { return x86_processor_flags_has(CPUID_AVX512F_BIT); } + + /** + * Check if the processor supports BMI2 + */ + static bool has_bmi2() + { return x86_processor_flags_has(CPUID_BMI2_BIT); } + + /** + * Check if the processor supports AES-NI + */ + static bool has_aes_ni() + { return x86_processor_flags_has(CPUID_AESNI_BIT); } + + /** + * Check if the processor supports CLMUL + */ + static bool has_clmul() + { return x86_processor_flags_has(CPUID_CLMUL_BIT); } + + /** + * Check if the processor supports Intel SHA extension + */ + static bool has_intel_sha() + { return x86_processor_flags_has(CPUID_SHA_BIT); } + + /** + * Check if the processor supports ADX extension + */ + static bool has_adx() + { return x86_processor_flags_has(CPUID_ADX_BIT); } + + /** + * Check if the processor supports RDRAND + */ + static bool has_rdrand() + { return x86_processor_flags_has(CPUID_RDRAND_BIT); } + + /** + * Check if the processor supports RDSEED + */ + static bool has_rdseed() + { return x86_processor_flags_has(CPUID_RDSEED_BIT); } + + /** + * Check if the processor supports AltiVec/VMX + */ + static bool has_altivec() { return m_altivec_capable; } + + static void print(std::ostream& o); + private: + enum CPUID_bits { + CPUID_RDTSC_BIT = 4, + CPUID_SSE2_BIT = 26, + CPUID_CLMUL_BIT = 33, + CPUID_SSSE3_BIT = 41, + CPUID_SSE41_BIT = 51, + CPUID_SSE42_BIT = 52, + CPUID_AESNI_BIT = 57, + CPUID_RDRAND_BIT = 62, + + CPUID_AVX2_BIT = 64+5, + CPUID_BMI2_BIT = 64+8, + CPUID_AVX512F_BIT = 64+16, + CPUID_RDSEED_BIT = 64+18, + CPUID_ADX_BIT = 64+19, + CPUID_SHA_BIT = 64+29, + }; + + static bool x86_processor_flags_has(u64bit bit) + { + return ((m_x86_processor_flags[bit/64] >> (bit % 64)) & 1); + } + + static u64bit m_x86_processor_flags[2]; + static size_t m_cache_line_size; + static bool m_altivec_capable; + }; + +} + +#endif diff --git a/src/lib/utils/datastor/datastor.cpp b/src/lib/utils/datastor/datastor.cpp new file mode 100644 index 000000000..7563e9309 --- /dev/null +++ b/src/lib/utils/datastor/datastor.cpp @@ -0,0 +1,165 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Data_Store Equality Comparison +*/ +bool Data_Store::operator==(const Data_Store& other) const + { + return (contents == other.contents); + } + +/* +* Check if this key has at least one value +*/ +bool Data_Store::has_value(const std::string& key) const + { + return (contents.lower_bound(key) != contents.end()); + } + +/* +* Search based on an arbitrary predicate +*/ +std::multimap Data_Store::search_for( + std::function predicate) const + { + std::multimap out; + + for(auto i = contents.begin(); i != contents.end(); ++i) + if(predicate(i->first, i->second)) + out.insert(std::make_pair(i->first, i->second)); + + return out; + } + +/* +* Search based on key equality +*/ +std::vector Data_Store::get(const std::string& looking_for) const + { + std::vector out; + auto range = contents.equal_range(looking_for); + for(auto i = range.first; i != range.second; ++i) + out.push_back(i->second); + return out; + } + +/* +* Get a single atom +*/ +std::string Data_Store::get1(const std::string& key) const + { + std::vector vals = get(key); + + if(vals.empty()) + throw Invalid_State("Data_Store::get1: No values set for " + key); + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + return vals[0]; + } + +std::string Data_Store::get1(const std::string& key, + const std::string& default_value) const + { + std::vector vals = get(key); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + if(vals.empty()) + return default_value; + + return vals[0]; + } + +/* +* Get a single std::vector atom +*/ +std::vector +Data_Store::get1_memvec(const std::string& key) const + { + std::vector vals = get(key); + + if(vals.empty()) + return std::vector(); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_memvec: Multiple values for " + + key); + + return hex_decode(vals[0]); + } + +/* +* Get a single u32bit atom +*/ +u32bit Data_Store::get1_u32bit(const std::string& key, + u32bit default_val) const + { + std::vector vals = get(key); + + if(vals.empty()) + return default_val; + else if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_u32bit: Multiple values for " + + key); + + return to_u32bit(vals[0]); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const std::string& val) + { + multimap_insert(contents, key, val); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, u32bit val) + { + add(key, std::to_string(val)); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const secure_vector& val) + { + add(key, hex_encode(&val[0], val.size())); + } + +void Data_Store::add(const std::string& key, const std::vector& val) + { + add(key, hex_encode(&val[0], val.size())); + } + +/* +* Insert a mapping of key/value pairs +*/ +void Data_Store::add(const std::multimap& in) + { + std::multimap::const_iterator i = in.begin(); + while(i != in.end()) + { + contents.insert(*i); + ++i; + } + } + +} diff --git a/src/lib/utils/datastor/datastor.h b/src/lib/utils/datastor/datastor.h new file mode 100644 index 000000000..1c0504fc9 --- /dev/null +++ b/src/lib/utils/datastor/datastor.h @@ -0,0 +1,57 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DATA_STORE_H__ +#define BOTAN_DATA_STORE_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Data Store +*/ +class BOTAN_DLL Data_Store + { + public: + /** + * A search function + */ + bool operator==(const Data_Store&) const; + + std::multimap search_for( + std::function predicate) const; + + std::vector get(const std::string&) const; + + std::string get1(const std::string& key) const; + + std::string get1(const std::string& key, + const std::string& default_value) const; + + std::vector get1_memvec(const std::string&) const; + u32bit get1_u32bit(const std::string&, u32bit = 0) const; + + bool has_value(const std::string&) const; + + void add(const std::multimap&); + void add(const std::string&, const std::string&); + void add(const std::string&, u32bit); + void add(const std::string&, const secure_vector&); + void add(const std::string&, const std::vector&); + private: + std::multimap contents; + }; + +} + +#endif diff --git a/src/lib/utils/datastor/info.txt b/src/lib/utils/datastor/info.txt new file mode 100644 index 000000000..b91fe5082 --- /dev/null +++ b/src/lib/utils/datastor/info.txt @@ -0,0 +1,3 @@ + +alloc + diff --git a/src/lib/utils/dyn_load/dyn_load.cpp b/src/lib/utils/dyn_load/dyn_load.cpp new file mode 100644 index 000000000..51afb1afe --- /dev/null +++ b/src/lib/utils/dyn_load/dyn_load.cpp @@ -0,0 +1,79 @@ +/** +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + #include +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + #include +#endif + +namespace Botan { + +namespace { + +void raise_runtime_loader_exception(const std::string& lib_name, + const char* msg) + { + throw std::runtime_error("Failed to load " + lib_name + ": " + + (msg ? msg : "Unknown error")); + } + +} + +Dynamically_Loaded_Library::Dynamically_Loaded_Library( + const std::string& library) : + lib_name(library), lib(nullptr) + { +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + lib = ::dlopen(lib_name.c_str(), RTLD_LAZY); + + if(!lib) + raise_runtime_loader_exception(lib_name, dlerror()); + +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + lib = ::LoadLibraryA(lib_name.c_str()); + + if(!lib) + raise_runtime_loader_exception(lib_name, "LoadLibrary failed"); +#endif + + if(!lib) + raise_runtime_loader_exception(lib_name, "Dynamic load not supported"); + } + +Dynamically_Loaded_Library::~Dynamically_Loaded_Library() + { +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + ::dlclose(lib); +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + ::FreeLibrary((HMODULE)lib); +#endif + } + +void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) + { + void* addr = nullptr; + +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + addr = ::dlsym(lib, symbol.c_str()); +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + addr = reinterpret_cast(::GetProcAddress((HMODULE)lib, + symbol.c_str())); +#endif + + if(!addr) + throw std::runtime_error("Failed to resolve symbol " + symbol + + " in " + lib_name); + + return addr; + } + +} diff --git a/src/lib/utils/dyn_load/dyn_load.h b/src/lib/utils/dyn_load/dyn_load.h new file mode 100644 index 000000000..9edaed202 --- /dev/null +++ b/src/lib/utils/dyn_load/dyn_load.h @@ -0,0 +1,67 @@ +/* +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DYNAMIC_LOADER_H__ +#define BOTAN_DYNAMIC_LOADER_H__ + +#include + +namespace Botan { + +/** +* Represents a DLL or shared object +*/ +class Dynamically_Loaded_Library + { + public: + /** + * Load a DLL (or fail with an exception) + * @param lib_name name or path to a library + * + * If you don't use a full path, the search order will be defined + * by whatever the system linker does by default. Always using fully + * qualified pathnames can help prevent code injection attacks (eg + * via manipulation of LD_LIBRARY_PATH on Linux) + */ + Dynamically_Loaded_Library(const std::string& lib_name); + + /** + * Unload the DLL + * @warning Any pointers returned by resolve()/resolve_symbol() + * should not be used after this destructor runs. + */ + ~Dynamically_Loaded_Library(); + + /** + * Load a symbol (or fail with an exception) + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + void* resolve_symbol(const std::string& symbol); + + /** + * Convenience function for casting symbol to the right type + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + template + T resolve(const std::string& symbol) + { + return reinterpret_cast(resolve_symbol(symbol)); + } + + private: + Dynamically_Loaded_Library(const Dynamically_Loaded_Library&); + Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&); + + std::string lib_name; + void* lib; + }; + +} + +#endif diff --git a/src/lib/utils/dyn_load/info.txt b/src/lib/utils/dyn_load/info.txt new file mode 100644 index 000000000..c8d91dd75 --- /dev/null +++ b/src/lib/utils/dyn_load/info.txt @@ -0,0 +1,24 @@ +define DYNAMIC_LOADER 20131128 + + +freebsd +linux +netbsd +openbsd +qnx +solaris +windows + + + +linux -> dl +solaris -> dl + + + +dyn_load.cpp + + + +dyn_load.h + diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h new file mode 100644 index 000000000..c480ffd48 --- /dev/null +++ b/src/lib/utils/exceptn.h @@ -0,0 +1,181 @@ +/* +* Exceptions +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EXCEPTION_H__ +#define BOTAN_EXCEPTION_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +typedef std::runtime_error Exception; +typedef std::invalid_argument Invalid_Argument; + +/** +* Invalid_State Exception +*/ +struct BOTAN_DLL Invalid_State : public Exception + { + Invalid_State(const std::string& err) : + Exception(err) + {} + }; + +/** +* Lookup_Error Exception +*/ +struct BOTAN_DLL Lookup_Error : public Exception + { + Lookup_Error(const std::string& err) : + Exception(err) + {} + }; + +/** +* Internal_Error Exception +*/ +struct BOTAN_DLL Internal_Error : public Exception + { + Internal_Error(const std::string& err) : + Exception("Internal error: " + err) + {} + }; + +/** +* Invalid_Key_Length Exception +*/ +struct BOTAN_DLL Invalid_Key_Length : public Invalid_Argument + { + Invalid_Key_Length(const std::string& name, size_t length) : + Invalid_Argument(name + " cannot accept a key of length " + + std::to_string(length)) + {} + }; + +/** +* Invalid_IV_Length Exception +*/ +struct BOTAN_DLL Invalid_IV_Length : public Invalid_Argument + { + Invalid_IV_Length(const std::string& mode, size_t bad_len) : + Invalid_Argument("IV length " + std::to_string(bad_len) + + " is invalid for " + mode) + {} + }; + +/** +* PRNG_Unseeded Exception +*/ +struct BOTAN_DLL PRNG_Unseeded : public Invalid_State + { + PRNG_Unseeded(const std::string& algo) : + Invalid_State("PRNG not seeded: " + algo) + {} + }; + +/** +* Policy_Violation Exception +*/ +struct BOTAN_DLL Policy_Violation : public Invalid_State + { + Policy_Violation(const std::string& err) : + Invalid_State("Policy violation: " + err) + {} + }; + +/** +* Algorithm_Not_Found Exception +*/ +struct BOTAN_DLL Algorithm_Not_Found : public Lookup_Error + { + Algorithm_Not_Found(const std::string& name) : + Lookup_Error("Could not find any algorithm named \"" + name + "\"") + {} + }; + +/** +* Invalid_Algorithm_Name Exception +*/ +struct BOTAN_DLL Invalid_Algorithm_Name : public Invalid_Argument + { + Invalid_Algorithm_Name(const std::string& name): + Invalid_Argument("Invalid algorithm name: " + name) + {} + }; + +/** +* Encoding_Error Exception +*/ +struct BOTAN_DLL Encoding_Error : public Invalid_Argument + { + Encoding_Error(const std::string& name) : + Invalid_Argument("Encoding error: " + name) {} + }; + +/** +* Decoding_Error Exception +*/ +struct BOTAN_DLL Decoding_Error : public Invalid_Argument + { + Decoding_Error(const std::string& name) : + Invalid_Argument("Decoding error: " + name) {} + }; + +/** +* Integrity_Failure Exception +*/ +struct BOTAN_DLL Integrity_Failure : public Exception + { + Integrity_Failure(const std::string& msg) : + Exception("Integrity failure: " + msg) {} + }; + +/** +* Invalid_OID Exception +*/ +struct BOTAN_DLL Invalid_OID : public Decoding_Error + { + Invalid_OID(const std::string& oid) : + Decoding_Error("Invalid ASN.1 OID: " + oid) {} + }; + +/** +* Stream_IO_Error Exception +*/ +struct BOTAN_DLL Stream_IO_Error : public Exception + { + Stream_IO_Error(const std::string& err) : + Exception("I/O error: " + err) + {} + }; + +/** +* Self Test Failure Exception +*/ +struct BOTAN_DLL Self_Test_Failure : public Internal_Error + { + Self_Test_Failure(const std::string& err) : + Internal_Error("Self test failed: " + err) + {} + }; + +/** +* Memory Allocation Exception +*/ +struct BOTAN_DLL Memory_Exhaustion : public std::bad_alloc + { + const char* what() const noexcept + { return "Ran out of memory, allocation failed"; } + }; + +} + +#endif diff --git a/src/lib/utils/get_byte.h b/src/lib/utils/get_byte.h new file mode 100644 index 000000000..6f8ef2632 --- /dev/null +++ b/src/lib/utils/get_byte.h @@ -0,0 +1,30 @@ +/* +* Read out bytes +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GET_BYTE_H__ +#define BOTAN_GET_BYTE_H__ + +#include + +namespace Botan { + +/** +* Byte extraction +* @param byte_num which byte to extract, 0 == highest byte +* @param input the value to extract from +* @return byte byte_num of input +*/ +template inline byte get_byte(size_t byte_num, T input) + { + return static_cast( + input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3) + ); + } + +} + +#endif diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp new file mode 100644 index 000000000..a233c1c60 --- /dev/null +++ b/src/lib/utils/http_util/http_util.cpp @@ -0,0 +1,220 @@ +/* +* Sketchy HTTP client +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BOOST_ASIO) +#include +#endif + +namespace Botan { + +namespace HTTP { + +#if defined(BOTAN_HAS_BOOST_ASIO) +std::string http_transact_asio(const std::string& hostname, + const std::string& message) + { + using namespace boost::asio::ip; + + boost::asio::ip::tcp::iostream tcp; + + tcp.connect(hostname, "http"); + + if(!tcp) + throw std::runtime_error("HTTP connection to " + hostname + " failed"); + + tcp << message; + tcp.flush(); + + std::ostringstream oss; + oss << tcp.rdbuf(); + + return oss.str(); + } +#endif + +std::string http_transact_fail(const std::string& hostname, + const std::string&) + { + throw std::runtime_error("Cannot connect to " + hostname + + ": network code disabled in build"); + } + +std::string url_encode(const std::string& in) + { + std::ostringstream out; + + for(auto c : in) + { + if(c >= 'A' && c <= 'Z') + out << c; + else if(c >= 'a' && c <= 'z') + out << c; + else if(c >= '0' && c <= '9') + out << c; + else if(c == '-' || c == '_' || c == '.' || c == '~') + out << c; + else + out << '%' << hex_encode(reinterpret_cast(&c), 1); + } + + return out.str(); + } + +std::ostream& operator<<(std::ostream& o, const Response& resp) + { + o << "HTTP " << resp.status_code() << " " << resp.status_message() << "\n"; + for(auto h : resp.headers()) + o << "Header '" << h.first << "' = '" << h.second << "'\n"; + o << "Body " << std::to_string(resp.body().size()) << " bytes:\n"; + o.write(reinterpret_cast(&resp.body()[0]), resp.body().size()); + return o; + } + +Response http_sync(http_exch_fn http_transact, + const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects) + { + const auto protocol_host_sep = url.find("://"); + if(protocol_host_sep == std::string::npos) + throw std::runtime_error("Invalid URL " + url); + const std::string protocol = url.substr(0, protocol_host_sep); + + const auto host_loc_sep = url.find('/', protocol_host_sep + 3); + + std::string hostname, loc; + + if(host_loc_sep == std::string::npos) + { + hostname = url.substr(protocol_host_sep + 3, std::string::npos); + loc = "/"; + } + else + { + hostname = url.substr(protocol_host_sep + 3, host_loc_sep-protocol_host_sep-3); + loc = url.substr(host_loc_sep, std::string::npos); + } + + std::ostringstream outbuf; + + outbuf << verb << " " << loc << " HTTP/1.0\r\n"; + outbuf << "Host: " << hostname << "\r\n"; + + if(verb == "GET") + { + outbuf << "Accept: */*\r\n"; + outbuf << "Cache-Control: no-cache\r\n"; + } + else if(verb == "POST") + outbuf << "Content-Length: " << body.size() << "\r\n"; + + if(content_type != "") + outbuf << "Content-Type: " << content_type << "\r\n"; + outbuf << "Connection: close\r\n\r\n"; + outbuf.write(reinterpret_cast(&body[0]), body.size()); + + std::istringstream io(http_transact(hostname, outbuf.str())); + + std::string line1; + std::getline(io, line1); + if(!io || line1.empty()) + throw std::runtime_error("No response"); + + std::stringstream response_stream(line1); + std::string http_version; + unsigned int status_code; + std::string status_message; + + response_stream >> http_version >> status_code; + + std::getline(response_stream, status_message); + + if(!response_stream || http_version.substr(0,5) != "HTTP/") + throw std::runtime_error("Not an HTTP response"); + + std::map headers; + std::string header_line; + while (std::getline(io, header_line) && header_line != "\r") + { + auto sep = header_line.find(": "); + if(sep == std::string::npos || sep > header_line.size() - 2) + throw std::runtime_error("Invalid HTTP header " + header_line); + const std::string key = header_line.substr(0, sep); + + if(sep + 2 < header_line.size() - 1) + { + const std::string val = header_line.substr(sep + 2, (header_line.size() - 1) - (sep + 2)); + headers[key] = val; + } + } + + if(status_code == 301 && headers.count("Location")) + { + if(allowable_redirects == 0) + throw std::runtime_error("HTTP redirection count exceeded"); + return GET_sync(headers["Location"], allowable_redirects - 1); + } + + // Use Content-Length if set + std::vector resp_body; + std::vector buf(4096); + while(io.good()) + { + io.read(reinterpret_cast(&buf[0]), buf.size()); + resp_body.insert(resp_body.end(), &buf[0], &buf[io.gcount()]); + } + + return Response(status_code, status_message, resp_body, headers); + } + +Response http_sync(const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects) + { + return http_sync( +#if defined(BOTAN_HAS_BOOST_ASIO) + http_transact_asio, +#else + http_transact_fail, +#endif + verb, + url, + content_type, + body, + allowable_redirects); + } + +Response GET_sync(const std::string& url, size_t allowable_redirects) + { + return http_sync("GET", url, "", std::vector(), allowable_redirects); + } + +Response POST_sync(const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects) + { + return http_sync("POST", url, content_type, body, allowable_redirects); + } + +std::future GET_async(const std::string& url, size_t allowable_redirects) + { + return std::async(std::launch::async, GET_sync, url, allowable_redirects); + } + +} + +} diff --git a/src/lib/utils/http_util/http_util.h b/src/lib/utils/http_util/http_util.h new file mode 100644 index 000000000..d024add4d --- /dev/null +++ b/src/lib/utils/http_util/http_util.h @@ -0,0 +1,97 @@ +/* +* HTTP utilities +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_UTILS_URLGET_H__ +#define BOTAN_UTILS_URLGET_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace HTTP { + +struct Response + { + public: + Response(unsigned int status_code, const std::string& status_message, + const std::vector& body, + const std::map& headers) : + m_status_code(status_code), + m_status_message(status_message), + m_body(body), + m_headers(headers) {} + + unsigned int status_code() const { return m_status_code; } + + const std::vector& body() const { return m_body; } + + const std::map& headers() const { return m_headers; } + + std::string status_message() const { return m_status_message; } + + void throw_unless_ok() + { + if(status_code() != 200) + throw std::runtime_error("HTTP error: " + status_message()); + } + + private: + unsigned int m_status_code; + std::string m_status_message; + std::vector m_body; + std::map m_headers; + }; + +BOTAN_DLL std::ostream& operator<<(std::ostream& o, const Response& resp); + +typedef std::function http_exch_fn; + +#if defined(BOTAN_HAS_BOOST_ASIO) +std::string BOTAN_DLL http_transact_asio(const std::string& hostname, + const std::string& message); +#endif + +std::string BOTAN_DLL http_transact_fail(const std::string& hostname, + const std::string& message); + + +BOTAN_DLL Response http_sync(http_exch_fn fn, + const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects); + +BOTAN_DLL Response http_sync(const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects); + +BOTAN_DLL Response GET_sync(const std::string& url, + size_t allowable_redirects = 1); + +BOTAN_DLL Response POST_sync(const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects = 1); + +std::future BOTAN_DLL GET_async(const std::string& url, + size_t allowable_redirects = 1); + +BOTAN_DLL std::string url_encode(const std::string& url); + +} + +} + +#endif diff --git a/src/lib/utils/http_util/info.txt b/src/lib/utils/http_util/info.txt new file mode 100644 index 000000000..a23a43a3d --- /dev/null +++ b/src/lib/utils/http_util/info.txt @@ -0,0 +1 @@ +define HTTP_UTIL 20131128 diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt new file mode 100644 index 000000000..0e8edeb00 --- /dev/null +++ b/src/lib/utils/info.txt @@ -0,0 +1,29 @@ +define UTIL_FUNCTIONS 20131128 + +load_on always + + +bit_ops.h +prefetch.h +rounding.h +semaphore.h +stl_util.h +xor_buf.h + + + +assert.h +bswap.h +calendar.h +charset.h +cpuid.h +exceptn.h +get_byte.h +loadstor.h +mem_ops.h +mul128.h +parsing.h +rotate.h +types.h +version.h + diff --git a/src/lib/utils/loadstor.h b/src/lib/utils/loadstor.h new file mode 100644 index 000000000..29e00592a --- /dev/null +++ b/src/lib/utils/loadstor.h @@ -0,0 +1,627 @@ +/* +* Load/Store Operators +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LOAD_STORE_H__ +#define BOTAN_LOAD_STORE_H__ + +#include +#include +#include +#include + +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + +#define BOTAN_ENDIAN_N2B(x) (x) +#define BOTAN_ENDIAN_B2N(x) (x) + +#define BOTAN_ENDIAN_N2L(x) reverse_bytes(x) +#define BOTAN_ENDIAN_L2N(x) reverse_bytes(x) + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + +#define BOTAN_ENDIAN_N2L(x) (x) +#define BOTAN_ENDIAN_L2N(x) (x) + +#define BOTAN_ENDIAN_N2B(x) reverse_bytes(x) +#define BOTAN_ENDIAN_B2N(x) reverse_bytes(x) + +#endif + +#endif + +namespace Botan { + +/** +* Make a u16bit from two bytes +* @param i0 the first byte +* @param i1 the second byte +* @return i0 || i1 +*/ +inline u16bit make_u16bit(byte i0, byte i1) + { + return ((static_cast(i0) << 8) | i1); + } + +/** +* Make a u32bit from four bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @return i0 || i1 || i2 || i3 +*/ +inline u32bit make_u32bit(byte i0, byte i1, byte i2, byte i3) + { + return ((static_cast(i0) << 24) | + (static_cast(i1) << 16) | + (static_cast(i2) << 8) | + (static_cast(i3))); + } + +/** +* Make a u32bit from eight bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @param i4 the fifth byte +* @param i5 the sixth byte +* @param i6 the seventh byte +* @param i7 the eighth byte +* @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7 +*/ +inline u64bit make_u64bit(byte i0, byte i1, byte i2, byte i3, + byte i4, byte i5, byte i6, byte i7) + { + return ((static_cast(i0) << 56) | + (static_cast(i1) << 48) | + (static_cast(i2) << 40) | + (static_cast(i3) << 32) | + (static_cast(i4) << 24) | + (static_cast(i5) << 16) | + (static_cast(i6) << 8) | + (static_cast(i7))); + } + +/** +* Load a big-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a big-endian value +*/ +template +inline T load_be(const byte in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[i]; + return out; + } + +/** +* Load a little-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a litte-endian value +*/ +template +inline T load_le(const byte in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[sizeof(T)-1-i]; + return out; + } + +/** +* Load a big-endian u16bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u16bit of in, as a big-endian value +*/ +template<> +inline u16bit load_be(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u16bit); + return make_u16bit(in[0], in[1]); +#endif + } + +/** +* Load a little-endian u16bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u16bit of in, as a little-endian value +*/ +template<> +inline u16bit load_le(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u16bit); + return make_u16bit(in[1], in[0]); +#endif + } + +/** +* Load a big-endian u32bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u32bit of in, as a big-endian value +*/ +template<> +inline u32bit load_be(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u32bit); + return make_u32bit(in[0], in[1], in[2], in[3]); +#endif + } + +/** +* Load a little-endian u32bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u32bit of in, as a little-endian value +*/ +template<> +inline u32bit load_le(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u32bit); + return make_u32bit(in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load a big-endian u64bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u64bit of in, as a big-endian value +*/ +template<> +inline u64bit load_be(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u64bit); + return make_u64bit(in[0], in[1], in[2], in[3], + in[4], in[5], in[6], in[7]); +#endif + } + +/** +* Load a little-endian u64bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u64bit of in, as a little-endian value +*/ +template<> +inline u64bit load_le(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u64bit); + return make_u64bit(in[7], in[6], in[5], in[4], + in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load two little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template +inline void load_le(const byte in[], T& x0, T& x1) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + } + +/** +* Load four little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template +inline void load_le(const byte in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + x2 = load_le(in, 2); + x3 = load_le(in, 3); + } + +/** +* Load eight little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template +inline void load_le(const byte in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + x2 = load_le(in, 2); + x3 = load_le(in, 3); + x4 = load_le(in, 4); + x5 = load_le(in, 5); + x6 = load_le(in, 6); + x7 = load_le(in, 7); + } + +/** +* Load a variable number of little-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template +inline void load_le(T out[], + const byte in[], + size_t count) + { +#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) + std::memcpy(out, in, sizeof(T)*count); + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#endif + +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_le(in, i); +#endif + } + +/** +* Load two big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template +inline void load_be(const byte in[], T& x0, T& x1) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + } + +/** +* Load four big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template +inline void load_be(const byte in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + x2 = load_be(in, 2); + x3 = load_be(in, 3); + } + +/** +* Load eight big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template +inline void load_be(const byte in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + x2 = load_be(in, 2); + x3 = load_be(in, 3); + x4 = load_be(in, 4); + x5 = load_be(in, 5); + x6 = load_be(in, 6); + x7 = load_be(in, 7); + } + +/** +* Load a variable number of big-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template +inline void load_be(T out[], + const byte in[], + size_t count) + { +#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) + std::memcpy(out, in, sizeof(T)*count); + +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#endif + +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_be(in, i); +#endif + } + +/** +* Store a big-endian u16bit +* @param in the input u16bit +* @param out the byte array to write to +*/ +inline void store_be(u16bit in, byte out[2]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); +#endif + } + +/** +* Store a little-endian u16bit +* @param in the input u16bit +* @param out the byte array to write to +*/ +inline void store_le(u16bit in, byte out[2]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(1, in); + out[1] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian u32bit +* @param in the input u32bit +* @param out the byte array to write to +*/ +inline void store_be(u32bit in, byte out[4]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); +#endif + } + +/** +* Store a little-endian u32bit +* @param in the input u32bit +* @param out the byte array to write to +*/ +inline void store_le(u32bit in, byte out[4]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(3, in); + out[1] = get_byte(2, in); + out[2] = get_byte(1, in); + out[3] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian u64bit +* @param in the input u64bit +* @param out the byte array to write to +*/ +inline void store_be(u64bit in, byte out[8]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); + out[4] = get_byte(4, in); + out[5] = get_byte(5, in); + out[6] = get_byte(6, in); + out[7] = get_byte(7, in); +#endif + } + +/** +* Store a little-endian u64bit +* @param in the input u64bit +* @param out the byte array to write to +*/ +inline void store_le(u64bit in, byte out[8]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(7, in); + out[1] = get_byte(6, in); + out[2] = get_byte(5, in); + out[3] = get_byte(4, in); + out[4] = get_byte(3, in); + out[5] = get_byte(2, in); + out[6] = get_byte(1, in); + out[7] = get_byte(0, in); +#endif + } + +/** +* Store two little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template +inline void store_le(byte out[], T x0, T x1) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + } + +/** +* Store two big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template +inline void store_be(byte out[], T x0, T x1) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + } + +/** +* Store four little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template +inline void store_le(byte out[], T x0, T x1, T x2, T x3) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + } + +/** +* Store four big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template +inline void store_be(byte out[], T x0, T x1, T x2, T x3) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + } + +/** +* Store eight little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template +inline void store_le(byte out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + store_le(x4, out + (4 * sizeof(T))); + store_le(x5, out + (5 * sizeof(T))); + store_le(x6, out + (6 * sizeof(T))); + store_le(x7, out + (7 * sizeof(T))); + } + +/** +* Store eight big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template +inline void store_be(byte out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + store_be(x4, out + (4 * sizeof(T))); + store_be(x5, out + (5 * sizeof(T))); + store_be(x6, out + (6 * sizeof(T))); + store_be(x7, out + (7 * sizeof(T))); + } + +} + +#endif diff --git a/src/lib/utils/mem_ops.h b/src/lib/utils/mem_ops.h new file mode 100644 index 000000000..be617ff19 --- /dev/null +++ b/src/lib/utils/mem_ops.h @@ -0,0 +1,75 @@ +/* +* Memory Operations +* (C) 1999-2009,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MEMORY_OPS_H__ +#define BOTAN_MEMORY_OPS_H__ + +#include +#include + +namespace Botan { + +/** +* Zeroize memory +* @param ptr a pointer to memory to zero out +* @param n the number of bytes pointed to by ptr +*/ +BOTAN_DLL void zero_mem(void* ptr, size_t n); + +/** +* Zeroize memory +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +*/ +template inline void clear_mem(T* ptr, size_t n) + { + zero_mem(ptr, sizeof(T)*n); + } + +/** +* Copy memory +* @param out the destination array +* @param in the source array +* @param n the number of elements of in/out +*/ +template inline void copy_mem(T* out, const T* in, size_t n) + { + std::memmove(out, in, sizeof(T)*n); + } + +/** +* Set memory to a fixed value +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +* @param val the value to set each byte to +*/ +template +inline void set_mem(T* ptr, size_t n, byte val) + { + std::memset(ptr, val, sizeof(T)*n); + } + +/** +* Memory comparison, input insensitive +* @param p1 a pointer to an array +* @param p2 a pointer to another array +* @param n the number of Ts in p1 and p2 +* @return true iff p1[i] == p2[i] forall i in [0...n) +*/ +template inline bool same_mem(const T* p1, const T* p2, size_t n) + { + volatile T difference = 0; + + for(size_t i = 0; i != n; ++i) + difference |= (p1[i] ^ p2[i]); + + return difference == 0; + } + +} + +#endif diff --git a/src/lib/utils/mul128.h b/src/lib/utils/mul128.h new file mode 100644 index 000000000..6725021ba --- /dev/null +++ b/src/lib/utils/mul128.h @@ -0,0 +1,121 @@ +/* +* 64x64->128 bit multiply operation +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_UTIL_MUL128_H__ +#define BOTAN_UTIL_MUL128_H__ + +#include + +namespace Botan { + +#if defined(__SIZEOF_INT128__) + #define BOTAN_TARGET_HAS_NATIVE_UINT128 + typedef unsigned __int128 uint128_t; + +#elif (BOTAN_GCC_VERSION > 440) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + #define BOTAN_TARGET_HAS_NATIVE_UINT128 + typedef unsigned int uint128_t __attribute__((mode(TI))); +#endif + +} + +#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { \ + const uint128_t r = static_cast(a) * b; \ + *hi = (r >> 64) & 0xFFFFFFFFFFFFFFFF; \ + *lo = (r ) & 0xFFFFFFFFFFFFFFFF; \ + } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + +#include +#pragma intrinsic(_umul128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { *lo = _umul128(a, b, hi); } while(0) + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulq %3" : "=d" (*hi), "=a" (*lo) : "a" (a), "rm" (b) : "cc"); \ + } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("umulh %1,%2,%0" : "=r" (*hi) : "r" (a), "r" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("xmpy.hu %0=%1,%2" : "=f" (*hi) : "f" (a), "f" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulhdu %0,%1,%2" : "=r" (*hi) : "r" (a), "r" (b) : "cc"); \ + *lo = a * b; \ +} while(0) + +#endif + +#endif + +namespace Botan { + +/** +* Perform a 64x64->128 bit multiplication +*/ +inline void mul64x64_128(u64bit a, u64bit b, u64bit* lo, u64bit* hi) + { +#if defined(BOTAN_FAST_64X64_MUL) + BOTAN_FAST_64X64_MUL(a, b, lo, hi); +#else + + /* + * Do a 64x64->128 multiply using four 32x32->64 multiplies plus + * some adds and shifts. Last resort for CPUs like UltraSPARC (with + * 64-bit registers/ALU, but no 64x64->128 multiply) or 32-bit CPUs. + */ + const size_t HWORD_BITS = 32; + const u32bit HWORD_MASK = 0xFFFFFFFF; + + const u32bit a_hi = (a >> HWORD_BITS); + const u32bit a_lo = (a & HWORD_MASK); + const u32bit b_hi = (b >> HWORD_BITS); + const u32bit b_lo = (b & HWORD_MASK); + + u64bit x0 = static_cast(a_hi) * b_hi; + u64bit x1 = static_cast(a_lo) * b_hi; + u64bit x2 = static_cast(a_hi) * b_lo; + u64bit x3 = static_cast(a_lo) * b_lo; + + // this cannot overflow as (2^32-1)^2 + 2^32-1 < 2^64-1 + x2 += x3 >> HWORD_BITS; + + // this one can overflow + x2 += x1; + + // propagate the carry if any + x0 += static_cast(static_cast(x2 < x1)) << HWORD_BITS; + + *hi = x0 + (x2 >> HWORD_BITS); + *lo = ((x2 & HWORD_MASK) << HWORD_BITS) + (x3 & HWORD_MASK); +#endif + } + +} + +#endif diff --git a/src/lib/utils/parsing.cpp b/src/lib/utils/parsing.cpp new file mode 100644 index 000000000..cf47e24f8 --- /dev/null +++ b/src/lib/utils/parsing.cpp @@ -0,0 +1,302 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +u32bit to_u32bit(const std::string& str) + { + return std::stoul(str, nullptr); + } + +/* +* Convert a string into a time duration +*/ +u32bit timespec_to_u32bit(const std::string& timespec) + { + if(timespec == "") + return 0; + + const char suffix = timespec[timespec.size()-1]; + std::string value = timespec.substr(0, timespec.size()-1); + + u32bit scale = 1; + + if(Charset::is_digit(suffix)) + value += suffix; + else if(suffix == 's') + scale = 1; + else if(suffix == 'm') + scale = 60; + else if(suffix == 'h') + scale = 60 * 60; + else if(suffix == 'd') + scale = 24 * 60 * 60; + else if(suffix == 'y') + scale = 365 * 24 * 60 * 60; + else + throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); + + return scale * to_u32bit(value); + } + +/* +* Parse a SCAN-style algorithm name +*/ +std::vector parse_algorithm_name(const std::string& namex) + { + if(namex.find('(') == std::string::npos && + namex.find(')') == std::string::npos) + return std::vector(1, namex); + + std::string name = namex, substring; + std::vector elems; + size_t level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for(auto i = name.begin(); i != name.end(); ++i) + { + char c = *i; + + if(c == '(') + ++level; + if(c == ')') + { + if(level == 1 && i == name.end() - 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + return elems; + } + + if(level == 0 || (level == 1 && i != name.end() - 1)) + throw Invalid_Algorithm_Name(namex); + --level; + } + + if(c == ',' && level == 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + substring.clear(); + } + else + substring += c; + } + + if(substring != "") + throw Invalid_Algorithm_Name(namex); + + return elems; + } + +/* +* Split the string on slashes +*/ +std::vector split_on(const std::string& str, char delim) + { + std::vector elems; + if(str == "") return elems; + + std::string substr; + for(auto i = str.begin(); i != str.end(); ++i) + { + if(*i == delim) + { + if(substr != "") + elems.push_back(substr); + substr.clear(); + } + else + substr += *i; + } + + if(substr == "") + throw Invalid_Argument("Unable to split string: " + str); + elems.push_back(substr); + + return elems; + } + +/* +* Join a string +*/ +std::string string_join(const std::vector& strs, char delim) + { + std::string out = ""; + + for(size_t i = 0; i != strs.size(); ++i) + { + if(i != 0) + out += delim; + out += strs[i]; + } + + return out; + } + +/* +* Parse an ASN.1 OID string +*/ +std::vector parse_asn1_oid(const std::string& oid) + { + std::string substring; + std::vector oid_elems; + + for(auto i = oid.begin(); i != oid.end(); ++i) + { + char c = *i; + + if(c == '.') + { + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + substring.clear(); + } + else + substring += c; + } + + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + + if(oid_elems.size() < 2) + throw Invalid_OID(oid); + + return oid_elems; + } + +/* +* X.500 String Comparison +*/ +bool x500_name_cmp(const std::string& name1, const std::string& name2) + { + auto p1 = name1.begin(); + auto p2 = name2.begin(); + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + while(p1 != name1.end() && p2 != name2.end()) + { + if(Charset::is_space(*p1)) + { + if(!Charset::is_space(*p2)) + return false; + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if(p1 == name1.end() && p2 == name2.end()) + return true; + } + + if(!Charset::caseless_cmp(*p1, *p2)) + return false; + ++p1; + ++p2; + } + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; + } + +/* +* Convert a decimal-dotted string to binary IP +*/ +u32bit string_to_ipv4(const std::string& str) + { + std::vector parts = split_on(str, '.'); + + if(parts.size() != 4) + throw Decoding_Error("Invalid IP string " + str); + + u32bit ip = 0; + + for(auto part = parts.begin(); part != parts.end(); ++part) + { + u32bit octet = to_u32bit(*part); + + if(octet > 255) + throw Decoding_Error("Invalid IP string " + str); + + ip = (ip << 8) | (octet & 0xFF); + } + + return ip; + } + +/* +* Convert an IP address to decimal-dotted string +*/ +std::string ipv4_to_string(u32bit ip) + { + std::string str; + + for(size_t i = 0; i != sizeof(ip); ++i) + { + if(i) + str += "."; + str += std::to_string(get_byte(i, ip)); + } + + return str; + } + +std::string erase_chars(const std::string& str, const std::set& chars) + { + std::string out; + + for(auto c: str) + if(chars.count(c) == 0) + out += c; + + return out; + } + +std::string replace_chars(const std::string& str, + const std::set& chars, + char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(chars.count(out[i])) + out[i] = to_char; + + return out; + } + +std::string replace_char(const std::string& str, char from_char, char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(out[i] == from_char) + out[i] = to_char; + + return out; + } + +} diff --git a/src/lib/utils/parsing.h b/src/lib/utils/parsing.h new file mode 100644 index 000000000..b37e3cb62 --- /dev/null +++ b/src/lib/utils/parsing.h @@ -0,0 +1,133 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PARSER_H__ +#define BOTAN_PARSER_H__ + +#include +#include +#include +#include + +#include +#include +#include + +namespace Botan { + +/** +* Parse a SCAN-style algorithm name +* @param scan_name the name +* @return the name components +*/ +BOTAN_DLL std::vector +parse_algorithm_name(const std::string& scan_name); + +/** +* Split a string +* @param str the input string +* @param delim the delimitor +* @return string split by delim +*/ +BOTAN_DLL std::vector split_on( + const std::string& str, char delim); + +/** +* Erase characters from a string +*/ +BOTAN_DLL std::string erase_chars(const std::string& str, const std::set& chars); + +/** +* Replace a character in a string +* @param str the input string +* @param from_char the character to replace +* @param to_char the character to replace it with +* @return str with all instances of from_char replaced by to_char +*/ +BOTAN_DLL std::string replace_char(const std::string& str, + char from_char, + char to_char); + +/** +* Replace a character in a string +* @param str the input string +* @param from_chars the characters to replace +* @param to_char the character to replace it with +* @return str with all instances of from_chars replaced by to_char +*/ +BOTAN_DLL std::string replace_chars(const std::string& str, + const std::set& from_chars, + char to_char); + +/** +* Join a string +* @param strs strings to join +* @param delim the delimitor +* @return string joined by delim +*/ +BOTAN_DLL std::string string_join(const std::vector& strs, + char delim); + +/** +* Parse an ASN.1 OID +* @param oid the OID in string form +* @return OID components +*/ +BOTAN_DLL std::vector parse_asn1_oid(const std::string& oid); + +/** +* Compare two names using the X.509 comparison algorithm +* @param name1 the first name +* @param name2 the second name +* @return true if name1 is the same as name2 by the X.509 comparison rules +*/ +BOTAN_DLL bool x500_name_cmp(const std::string& name1, + const std::string& name2); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_DLL u32bit to_u32bit(const std::string& str); + +/** +* Convert a time specification to a number +* @param timespec the time specification +* @return number of seconds represented by timespec +*/ +BOTAN_DLL u32bit timespec_to_u32bit(const std::string& timespec); + +/** +* Convert a string representation of an IPv4 address to a number +* @param ip_str the string representation +* @return integer IPv4 address +*/ +BOTAN_DLL u32bit string_to_ipv4(const std::string& ip_str); + +/** +* Convert an IPv4 address to a string +* @param ip_addr the IPv4 address to convert +* @return string representation of the IPv4 address +*/ +BOTAN_DLL std::string ipv4_to_string(u32bit ip_addr); + +void BOTAN_DLL lex_cfg(std::istream& is, + std::function cb); + +void BOTAN_DLL lex_cfg_w_headers(std::istream& is, + std::function cb, + std::function header_cb); + +std::map> +BOTAN_DLL +parse_cfg(std::istream& is); + + +} + +#endif diff --git a/src/lib/utils/prefetch.h b/src/lib/utils/prefetch.h new file mode 100644 index 000000000..66024e5ce --- /dev/null +++ b/src/lib/utils/prefetch.h @@ -0,0 +1,39 @@ +/* +* Prefetching Operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PREFETCH_H__ +#define BOTAN_PREFETCH_H__ + +#include + +namespace Botan { + +template +inline void prefetch_readonly(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 0); +#endif + } + +template +inline void prefetch_readwrite(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 1); +#endif + } + +} + +#endif diff --git a/src/lib/utils/read_cfg.cpp b/src/lib/utils/read_cfg.cpp new file mode 100644 index 000000000..ad57a8b3e --- /dev/null +++ b/src/lib/utils/read_cfg.cpp @@ -0,0 +1,115 @@ +/* +* Simple config/test file reader +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +void lex_cfg(std::istream& is, + std::function cb) + { + while(is.good()) + { + std::string s; + + std::getline(is, s); + + while(is.good() && s.back() == '\\') + { + boost::trim_if(s, boost::is_any_of("\\\n")); + std::string x; + std::getline(is, x); + boost::trim_left(x); + s += x; + } + + auto comment = s.find('#'); + if(comment) + s = s.substr(0, comment); + + if(s.empty()) + continue; + + std::vector parts; + boost::split(parts, s, boost::is_any_of(" \t\n"), boost::token_compress_on); + + for(auto p : parts) + { + if(p.empty()) + continue; + + auto eq = p.find("="); + + if(eq == std::string::npos || p.size() < 2) + { + cb(p); + } + else if(eq == 0) + { + cb("="); + cb(p.substr(1, std::string::npos)); + } + else if(eq == p.size() - 1) + { + cb(p.substr(0, p.size() - 1)); + cb("="); + } + else if(eq != std::string::npos) + { + cb(p.substr(0, eq)); + cb("="); + cb(p.substr(eq + 1, std::string::npos)); + } + } + } + } + +void lex_cfg_w_headers(std::istream& is, + std::function cb, + std::function hdr_cb) + { + auto intercept = [cb,hdr_cb](const std::string& s) + { + if(s[0] == '[' && s[s.length()-1] == ']') + hdr_cb(s.substr(1, s.length()-2)); + else + cb(s); + }; + + lex_cfg(is, intercept); + } + +std::map> + parse_cfg(std::istream& is) + { + std::string header = "default"; + std::map> vals; + std::string key; + + auto header_cb = [&header](const std::string i) { header = i; }; + auto cb = [&header,&key,&vals](const std::string s) + { + if(s == "=") + { + BOTAN_ASSERT(!key.empty(), "Valid assignment in config"); + } + else if(key.empty()) + key = s; + else + { + vals[header][key] = s; + key = ""; + } + }; + + lex_cfg_w_headers(is, cb, header_cb); + + return vals; + } + +} diff --git a/src/lib/utils/rotate.h b/src/lib/utils/rotate.h new file mode 100644 index 000000000..2593010b4 --- /dev/null +++ b/src/lib/utils/rotate.h @@ -0,0 +1,43 @@ +/* +* Word Rotation Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_WORD_ROTATE_H__ +#define BOTAN_WORD_ROTATE_H__ + +#include + +namespace Botan { + +/** +* Bit rotation left +* @param input the input word +* @param rot the number of bits to rotate +* @return input rotated left by rot bits +*/ +template inline T rotate_left(T input, size_t rot) + { + if(rot == 0) + return input; + return static_cast((input << rot) | (input >> (8*sizeof(T)-rot)));; + } + +/** +* Bit rotation right +* @param input the input word +* @param rot the number of bits to rotate +* @return input rotated right by rot bits +*/ +template inline T rotate_right(T input, size_t rot) + { + if(rot == 0) + return input; + return static_cast((input >> rot) | (input << (8*sizeof(T)-rot))); + } + +} + +#endif diff --git a/src/lib/utils/rounding.h b/src/lib/utils/rounding.h new file mode 100644 index 000000000..4ddd7a432 --- /dev/null +++ b/src/lib/utils/rounding.h @@ -0,0 +1,61 @@ +/* +* Integer Rounding Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ROUNDING_H__ +#define BOTAN_ROUNDING_H__ + +#include + +namespace Botan { + +/** +* Round up +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded up to a multiple of align_to +*/ +template +inline T round_up(T n, T align_to) + { + if(align_to == 0) + return n; + + if(n % align_to || n == 0) + n += align_to - (n % align_to); + return n; + } + +/** +* Round down +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded down to a multiple of align_to +*/ +template +inline T round_down(T n, T align_to) + { + if(align_to == 0) + return n; + + return (n - (n % align_to)); + } + +/** +* Clamp +*/ +inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound) + { + if(n < lower_bound) + return lower_bound; + if(n > upper_bound) + return upper_bound; + return n; + } + +} + +#endif diff --git a/src/lib/utils/semaphore.cpp b/src/lib/utils/semaphore.cpp new file mode 100644 index 000000000..f4f5b2b53 --- /dev/null +++ b/src/lib/utils/semaphore.cpp @@ -0,0 +1,39 @@ +/* +* Semaphore +* by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html) +* modified by Joel Low for Botan +* +*/ + +#include + +namespace Botan { + +void Semaphore::release(size_t n) + { + for(size_t i = 0; i != n; ++i) + { + std::lock_guard lock(m_mutex); + + ++m_value; + + if(m_value <= 0) + { + ++m_wakeups; + m_cond.notify_one(); + } + } + } + +void Semaphore::acquire() + { + std::unique_lock lock(m_mutex); + --m_value; + if(m_value < 0) + { + m_cond.wait(lock, [this] { return m_wakeups > 0; }); + --m_wakeups; + } + } + +} diff --git a/src/lib/utils/semaphore.h b/src/lib/utils/semaphore.h new file mode 100644 index 000000000..c3ce73680 --- /dev/null +++ b/src/lib/utils/semaphore.h @@ -0,0 +1,34 @@ +/* +* Semaphore +* by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html) +* modified by Joel Low for Botan +* +*/ + +#ifndef BOTAN_SEMAPHORE_H__ +#define BOTAN_SEMAPHORE_H__ + +#include +#include + +namespace Botan { + +class Semaphore + { + public: + Semaphore(int value = 0) : m_value(value), m_wakeups(0) {} + + void acquire(); + + void release(size_t n = 1); + + private: + int m_value; + int m_wakeups; + std::mutex m_mutex; + std::condition_variable m_cond; + }; + +} + +#endif diff --git a/src/lib/utils/sqlite3/info.txt b/src/lib/utils/sqlite3/info.txt new file mode 100644 index 000000000..97d59d697 --- /dev/null +++ b/src/lib/utils/sqlite3/info.txt @@ -0,0 +1,14 @@ + +load_on request + + +all -> sqlite3 + + + +sqlite3.h + + + +sqlite3.cpp + diff --git a/src/lib/utils/sqlite3/sqlite3.cpp b/src/lib/utils/sqlite3/sqlite3.cpp new file mode 100644 index 000000000..7f6626759 --- /dev/null +++ b/src/lib/utils/sqlite3/sqlite3.cpp @@ -0,0 +1,137 @@ +/* +* SQLite wrapper +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +sqlite3_database::sqlite3_database(const std::string& db_filename) + { + int rc = ::sqlite3_open(db_filename.c_str(), &m_db); + + if(rc) + { + const std::string err_msg = ::sqlite3_errmsg(m_db); + ::sqlite3_close(m_db); + m_db = nullptr; + throw std::runtime_error("sqlite3_open failed - " + err_msg); + } + } + +sqlite3_database::~sqlite3_database() + { + if(m_db) + ::sqlite3_close(m_db); + m_db = nullptr; + } + +size_t sqlite3_database::row_count(const std::string& table_name) + { + sqlite3_statement stmt(this, "select count(*) from " + table_name); + + if(stmt.step()) + return stmt.get_size_t(0); + else + throw std::runtime_error("Querying size of table " + table_name + " failed"); + } + +void sqlite3_database::create_table(const std::string& table_schema) + { + char* errmsg = nullptr; + int rc = ::sqlite3_exec(m_db, table_schema.c_str(), nullptr, nullptr, &errmsg); + + if(rc != SQLITE_OK) + { + const std::string err_msg = errmsg; + ::sqlite3_free(errmsg); + ::sqlite3_close(m_db); + m_db = nullptr; + throw std::runtime_error("sqlite3_exec for table failed - " + err_msg); + } + } + + +sqlite3_statement::sqlite3_statement(sqlite3_database* db, const std::string& base_sql) + { + int rc = ::sqlite3_prepare_v2(db->m_db, base_sql.c_str(), -1, &m_stmt, nullptr); + + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_prepare failed " + base_sql + + ", code " + std::to_string(rc)); + } + +void sqlite3_statement::bind(int column, const std::string& val) + { + int rc = ::sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc)); + } + +void sqlite3_statement::bind(int column, int val) + { + int rc = ::sqlite3_bind_int(m_stmt, column, val); + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_bind_int failed, code " + std::to_string(rc)); + } + +void sqlite3_statement::bind(int column, std::chrono::system_clock::time_point time) + { + const int timeval = std::chrono::duration_cast(time.time_since_epoch()).count(); + bind(column, timeval); + } + +void sqlite3_statement::bind(int column, const std::vector& val) + { + int rc = ::sqlite3_bind_blob(m_stmt, column, &val[0], val.size(), SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc)); + } + +std::pair sqlite3_statement::get_blob(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB, + "Return value is a blob"); + + const void* session_blob = ::sqlite3_column_blob(m_stmt, column); + const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column); + + BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative"); + + return std::make_pair(static_cast(session_blob), + static_cast(session_blob_size)); + } + +size_t sqlite3_statement::get_size_t(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER, + "Return count is an integer"); + + const int sessions_int = ::sqlite3_column_int(m_stmt, column); + + BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative"); + + return static_cast(sessions_int); + } + +void sqlite3_statement::spin() + { + while(step()) {} + } + +bool sqlite3_statement::step() + { + return (::sqlite3_step(m_stmt) == SQLITE_ROW); + } + +sqlite3_statement::~sqlite3_statement() + { + ::sqlite3_finalize(m_stmt); + } + +} diff --git a/src/lib/utils/sqlite3/sqlite3.h b/src/lib/utils/sqlite3/sqlite3.h new file mode 100644 index 000000000..aef04ab4d --- /dev/null +++ b/src/lib/utils/sqlite3/sqlite3.h @@ -0,0 +1,68 @@ +/* +* SQLite wrapper +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_UTILS_SQLITE_WRAPPER_H__ +#define BOTAN_UTILS_SQLITE_WRAPPER_H__ + +#include +#include +#include +#include + +class sqlite3; +class sqlite3_stmt; + +namespace Botan { + +class sqlite3_database + { + public: + sqlite3_database(const std::string& file); + + ~sqlite3_database(); + + size_t row_count(const std::string& table_name); + + void create_table(const std::string& table_schema); + private: + friend class sqlite3_statement; + + sqlite3* m_db; + }; + +class sqlite3_statement + { + public: + sqlite3_statement(sqlite3_database* db, + const std::string& base_sql); + + void bind(int column, const std::string& val); + + void bind(int column, int val); + + void bind(int column, std::chrono::system_clock::time_point time); + + void bind(int column, const std::vector& val); + + std::pair get_blob(int column); + + size_t get_size_t(int column); + + void spin(); + + bool step(); + + sqlite3_stmt* stmt() { return m_stmt; } + + ~sqlite3_statement(); + private: + sqlite3_stmt* m_stmt; + }; + +} + +#endif diff --git a/src/lib/utils/stl_util.h b/src/lib/utils/stl_util.h new file mode 100644 index 000000000..0710d61a5 --- /dev/null +++ b/src/lib/utils/stl_util.h @@ -0,0 +1,94 @@ +/* +* STL Utility Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_STL_UTIL_H__ +#define BOTAN_STL_UTIL_H__ + +#include +#include +#include + +namespace Botan { + +inline std::vector to_byte_vector(const std::string& s) + { + return std::vector(reinterpret_cast(&s[0]), + reinterpret_cast(&s[s.size()])); + } + +/* +* Searching through a std::map +* @param mapping the map to search +* @param key is what to look for +* @param null_result is the value to return if key is not in mapping +* @return mapping[key] or null_result +*/ +template +inline V search_map(const std::map& mapping, + const K& key, + const V& null_result = V()) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return i->second; + } + +template +inline R search_map(const std::map& mapping, const K& key, + const R& null_result, const R& found_result) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return found_result; + } + +/* +* Insert a key/value pair into a multimap +*/ +template +void multimap_insert(std::multimap& multimap, + const K& key, const V& value) + { +#if defined(BOTAN_BUILD_COMPILER_IS_SUN_STUDIO) + // Work around a strange bug in Sun Studio + multimap.insert(std::make_pair(key, value)); +#else + multimap.insert(std::make_pair(key, value)); +#endif + } + +/** +* Existence check for values +*/ +template +bool value_exists(const std::vector& vec, + const T& val) + { + for(size_t i = 0; i != vec.size(); ++i) + if(vec[i] == val) + return true; + return false; + } + +template +void map_remove_if(Pred pred, T& assoc) + { + auto i = assoc.begin(); + while(i != assoc.end()) + { + if(pred(i->first)) + assoc.erase(i++); + else + i++; + } + } + +} + +#endif diff --git a/src/lib/utils/types.h b/src/lib/utils/types.h new file mode 100644 index 000000000..f4a2eeacd --- /dev/null +++ b/src/lib/utils/types.h @@ -0,0 +1,48 @@ +/* +* Low Level Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TYPES_H__ +#define BOTAN_TYPES_H__ + +#include +#include +#include +#include + +/** +* The primary namespace for the botan library +*/ +namespace Botan { + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::size_t; + +typedef uint8_t byte; +typedef uint16_t u16bit; +typedef uint32_t u32bit; +typedef uint64_t u64bit; + +typedef std::int32_t s32bit; + +/** +* A default buffer size; typically a memory page +*/ +static const size_t DEFAULT_BUFFERSIZE = BOTAN_DEFAULT_BUFFER_SIZE; + +} + +namespace Botan_types { + +using Botan::byte; +using Botan::u32bit; + +} + +#endif diff --git a/src/lib/utils/version.cpp b/src/lib/utils/version.cpp new file mode 100644 index 000000000..32679cf63 --- /dev/null +++ b/src/lib/utils/version.cpp @@ -0,0 +1,55 @@ +/* +* Version Information +* (C) 1999-2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* + These are intentionally compiled rather than inlined, so an + application running against a shared library can test the true + version they are running against. +*/ + +/* +* Return the version as a string +*/ +std::string version_string() + { +#define QUOTE(name) #name +#define STR(macro) QUOTE(macro) + + /* + It is intentional that this string is a compile-time constant; + it makes it much easier to find in binaries. + */ + + return "Botan " STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH) " (" + BOTAN_VERSION_RELEASE_TYPE +#if (BOTAN_VERSION_DATESTAMP != 0) + ", dated " STR(BOTAN_VERSION_DATESTAMP) +#endif + ", revision " BOTAN_VERSION_VC_REVISION + ", distribution " BOTAN_DISTRIBUTION_INFO ")"; + +#undef STR +#undef QUOTE + } + +u32bit version_datestamp() { return BOTAN_VERSION_DATESTAMP; } + +/* +* Return parts of the version as integers +*/ +u32bit version_major() { return BOTAN_VERSION_MAJOR; } +u32bit version_minor() { return BOTAN_VERSION_MINOR; } +u32bit version_patch() { return BOTAN_VERSION_PATCH; } + +} diff --git a/src/lib/utils/version.h b/src/lib/utils/version.h new file mode 100644 index 000000000..219c261a5 --- /dev/null +++ b/src/lib/utils/version.h @@ -0,0 +1,72 @@ +/* +* Version Information +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_VERSION_H__ +#define BOTAN_VERSION_H__ + +#include +#include + +namespace Botan { + +/* +* Get information describing the version +*/ + +/** +* Get a human-readable string identifying the version of Botan. +* No particular format should be assumed. +* @return version string +*/ +BOTAN_DLL std::string version_string(); + +/** +* Return the date this version of botan was released, in an integer of +* the form YYYYMMDD. For instance a version released on May 21, 2013 +* would return the integer 20130521. If the currently running version +* is not an official release, this function will return 0 instead. +* +* @return release date, or zero if unreleased +*/ +BOTAN_DLL u32bit version_datestamp(); + +/** +* Get the major version number. +* @return major version number +*/ +BOTAN_DLL u32bit version_major(); + +/** +* Get the minor version number. +* @return minor version number +*/ +BOTAN_DLL u32bit version_minor(); + +/** +* Get the patch number. +* @return patch number +*/ +BOTAN_DLL u32bit version_patch(); + +/* +* Macros for compile-time version checks +*/ +#define BOTAN_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +/** +* Compare using BOTAN_VERSION_CODE_FOR, as in +* # if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,8,0) +* # error "Botan version too old" +* # endif +*/ +#define BOTAN_VERSION_CODE BOTAN_VERSION_CODE_FOR(BOTAN_VERSION_MAJOR, \ + BOTAN_VERSION_MINOR, \ + BOTAN_VERSION_PATCH) + +} + +#endif diff --git a/src/lib/utils/xor_buf.h b/src/lib/utils/xor_buf.h new file mode 100644 index 000000000..5773a619c --- /dev/null +++ b/src/lib/utils/xor_buf.h @@ -0,0 +1,113 @@ +/* +* XOR operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_XOR_BUF_H__ +#define BOTAN_XOR_BUF_H__ + +#include +#include + +namespace Botan { + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length +* @param out the input/output buffer +* @param in the read-only input buffer +* @param length the length of the buffers +*/ +inline void xor_buf(byte out[], const byte in[], size_t length) + { + while(length >= 8) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) ^= *reinterpret_cast(in); +#else + out[0] ^= in[0]; out[1] ^= in[1]; + out[2] ^= in[2]; out[3] ^= in[3]; + out[4] ^= in[4]; out[5] ^= in[5]; + out[6] ^= in[6]; out[7] ^= in[7]; +#endif + + out += 8; in += 8; length -= 8; + } + + for(size_t i = 0; i != length; ++i) + out[i] ^= in[i]; + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length +* @param out the output buffer +* @param in the first input buffer +* @param in2 the second output buffer +* @param length the length of the three buffers +*/ +inline void xor_buf(byte out[], + const byte in[], + const byte in2[], + size_t length) + { + while(length >= 8) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = + *reinterpret_cast(in) ^ + *reinterpret_cast(in2); +#else + out[0] = in[0] ^ in2[0]; out[1] = in[1] ^ in2[1]; + out[2] = in[2] ^ in2[2]; out[3] = in[3] ^ in2[3]; + out[4] = in[4] ^ in2[4]; out[5] = in[5] ^ in2[5]; + out[6] = in[6] ^ in2[6]; out[7] = in[7] ^ in2[7]; +#endif + + in += 8; in2 += 8; out += 8; length -= 8; + } + + for(size_t i = 0; i != length; ++i) + out[i] = in[i] ^ in2[i]; + } + +template +void xor_buf(std::vector& out, + const std::vector& in, + size_t n) + { + xor_buf(&out[0], &in[0], n); + } + +template +void xor_buf(std::vector& out, + const byte* in, + size_t n) + { + xor_buf(&out[0], in, n); + } + +template +void xor_buf(std::vector& out, + const byte* in, + const std::vector& in2, + size_t n) + { + xor_buf(&out[0], &in[0], &in2[0], n); + } + +template +std::vector& +operator^=(std::vector& out, + const std::vector& in) + { + if(out.size() < in.size()) + out.resize(in.size()); + + xor_buf(&out[0], &in[0], in.size()); + return out; + } + +} + +#endif diff --git a/src/lib/utils/zero_mem.cpp b/src/lib/utils/zero_mem.cpp new file mode 100644 index 000000000..e812ced0c --- /dev/null +++ b/src/lib/utils/zero_mem.cpp @@ -0,0 +1,20 @@ +/* +* Zero Memory +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +void zero_mem(void* ptr, size_t n) + { + volatile byte* p = reinterpret_cast(ptr); + + for(size_t i = 0; i != n; ++i) + p[i] = 0; + } + +} -- cgit v1.2.3