# # delete_file "cryptopp/algebra.cpp" # # delete_file "cryptopp/algebra.h" # # delete_file "cryptopp/algparam.cpp" # # delete_file "cryptopp/algparam.h" # # delete_file "cryptopp/arc4.cpp" # # delete_file "cryptopp/arc4.h" # # delete_file "cryptopp/argnames.h" # # delete_file "cryptopp/asn.cpp" # # delete_file "cryptopp/asn.h" # # delete_file "cryptopp/base64.cpp" # # delete_file "cryptopp/base64.h" # # delete_file "cryptopp/basecode.cpp" # # delete_file "cryptopp/basecode.h" # # delete_file "cryptopp/config.h" # # delete_file "cryptopp/crc.cpp" # # delete_file "cryptopp/crc.h" # # delete_file "cryptopp/cryptlib.cpp" # # delete_file "cryptopp/cryptlib.h" # # delete_file "cryptopp/des.cpp" # # delete_file "cryptopp/des.h" # # delete_file "cryptopp/dessp.cpp" # # delete_file "cryptopp/dll.cpp" # # delete_file "cryptopp/dll.h" # # delete_file "cryptopp/eprecomp.cpp" # # delete_file "cryptopp/eprecomp.h" # # delete_file "cryptopp/files.cpp" # # delete_file "cryptopp/files.h" # # delete_file "cryptopp/filters.cpp" # # delete_file "cryptopp/filters.h" # # delete_file "cryptopp/fips140.cpp" # # delete_file "cryptopp/fips140.h" # # delete_file "cryptopp/fltrimpl.h" # # delete_file "cryptopp/gzip.cpp" # # delete_file "cryptopp/gzip.h" # # delete_file "cryptopp/hex.cpp" # # delete_file "cryptopp/hex.h" # # delete_file "cryptopp/hmac.cpp" # # delete_file "cryptopp/hmac.h" # # delete_file "cryptopp/integer.cpp" # # delete_file "cryptopp/integer.h" # # delete_file "cryptopp/iterhash.cpp" # # delete_file "cryptopp/iterhash.h" # # delete_file "cryptopp/mdc.h" # # delete_file "cryptopp/misc.cpp" # # delete_file "cryptopp/misc.h" # # delete_file "cryptopp/modarith.h" # # delete_file "cryptopp/modes.cpp" # # delete_file "cryptopp/modes.h" # # delete_file "cryptopp/mqueue.cpp" # # delete_file "cryptopp/mqueue.h" # # delete_file "cryptopp/nbtheory.cpp" # # delete_file "cryptopp/nbtheory.h" # # delete_file "cryptopp/oaep.cpp" # # delete_file "cryptopp/oaep.h" # # delete_file "cryptopp/oids.h" # # delete_file "cryptopp/osrng.cpp" # # delete_file "cryptopp/osrng.h" # # delete_file "cryptopp/pch.cpp" # # delete_file "cryptopp/pch.h" # # delete_file "cryptopp/pkcspad.cpp" # # delete_file "cryptopp/pkcspad.h" # # delete_file "cryptopp/pssr.cpp" # # delete_file "cryptopp/pssr.h" # # delete_file "cryptopp/pubkey.cpp" # # delete_file "cryptopp/pubkey.h" # # delete_file "cryptopp/queue.cpp" # # delete_file "cryptopp/queue.h" # # delete_file "cryptopp/randpool.cpp" # # delete_file "cryptopp/randpool.h" # # delete_file "cryptopp/rng.cpp" # # delete_file "cryptopp/rng.h" # # delete_file "cryptopp/rsa.cpp" # # delete_file "cryptopp/rsa.h" # # delete_file "cryptopp/secblock.h" # # delete_file "cryptopp/seckey.h" # # delete_file "cryptopp/sha.cpp" # # delete_file "cryptopp/sha.h" # # delete_file "cryptopp/simple.h" # # delete_file "cryptopp/smartptr.h" # # delete_file "cryptopp/stdcpp.h" # # delete_file "cryptopp/strciphr.cpp" # # delete_file "cryptopp/strciphr.h" # # delete_file "cryptopp/trdlocal.cpp" # # delete_file "cryptopp/trdlocal.h" # # delete_file "cryptopp/words.h" # # delete_file "cryptopp/zdeflate.cpp" # # delete_file "cryptopp/zdeflate.h" # # delete_file "cryptopp/zinflate.cpp" # # delete_file "cryptopp/zinflate.h" # # add_file "botan/aes.cpp" # # add_file "botan/aes.h" # # add_file "botan/aes_tab.cpp" # # add_file "botan/algolist.cpp" # # add_file "botan/algolist.h" # # add_file "botan/allocate.cpp" # # add_file "botan/allocate.h" # # add_file "botan/arc4.cpp" # # add_file "botan/arc4.h" # # add_file "botan/asn1.h" # # add_file "botan/asn1_alg.cpp" # # add_file "botan/asn1_alt.cpp" # # add_file "botan/asn1_att.cpp" # # add_file "botan/asn1_dn.cpp" # # add_file "botan/asn1_ext.cpp" # # add_file "botan/asn1_ku.cpp" # # add_file "botan/asn1_obj.h" # # add_file "botan/asn1_oid.cpp" # # add_file "botan/asn1_oid.h" # # add_file "botan/asn1_str.cpp" # # add_file "botan/asn1_tm.cpp" # # add_file "botan/authors.txt" # # add_file "botan/barrett.cpp" # # add_file "botan/barrett.h" # # add_file "botan/base.cpp" # # add_file "botan/base.h" # # add_file "botan/base64.cpp" # # add_file "botan/base64.h" # # add_file "botan/base_eng.h" # # add_file "botan/basefilt.cpp" # # add_file "botan/basefilt.h" # # add_file "botan/ber_code.cpp" # # add_file "botan/ber_dec.cpp" # # add_file "botan/ber_dec.h" # # add_file "botan/big_base.cpp" # # add_file "botan/big_code.cpp" # # add_file "botan/big_io.cpp" # # add_file "botan/big_ops2.cpp" # # add_file "botan/big_ops3.cpp" # # add_file "botan/bigint.h" # # add_file "botan/blinding.cpp" # # add_file "botan/blinding.h" # # add_file "botan/botan.h" # # add_file "botan/buf_es.cpp" # # add_file "botan/buf_es.h" # # add_file "botan/buf_filt.cpp" # # add_file "botan/buf_filt.h" # # add_file "botan/cbc.cpp" # # add_file "botan/cbc.h" # # add_file "botan/certstor.h" # # add_file "botan/certstore.cpp" # # add_file "botan/cfb.cpp" # # add_file "botan/cfb.h" # # add_file "botan/charset.cpp" # # add_file "botan/conf.cpp" # # add_file "botan/conf.h" # # add_file "botan/config.h" # # add_file "botan/crc32.cpp" # # add_file "botan/crc32.h" # # add_file "botan/crl_ent.cpp" # # add_file "botan/crl_ent.h" # # add_file "botan/ctr.cpp" # # add_file "botan/ctr.h" # # add_file "botan/cts.cpp" # # add_file "botan/cts.h" # # add_file "botan/data_snk.cpp" # # add_file "botan/data_snk.h" # # add_file "botan/data_src.cpp" # # add_file "botan/data_src.h" # # add_file "botan/def_eng.cpp" # # add_file "botan/def_eng.h" # # add_file "botan/def_ops.cpp" # # add_file "botan/defalloc.cpp" # # add_file "botan/defalloc.h" # # add_file "botan/der_code.cpp" # # add_file "botan/der_enc.cpp" # # add_file "botan/der_enc.h" # # add_file "botan/dh.cpp" # # add_file "botan/dh.h" # # add_file "botan/divide.cpp" # # add_file "botan/dl_algo.cpp" # # add_file "botan/dl_algo.h" # # add_file "botan/dl_get.cpp" # # add_file "botan/dl_group.cpp" # # add_file "botan/dl_param.cpp" # # add_file "botan/dl_param.h" # # add_file "botan/dlies.cpp" # # add_file "botan/dlies.h" # # add_file "botan/eax.cpp" # # add_file "botan/eax.h" # # add_file "botan/ecb.cpp" # # add_file "botan/ecb.h" # # add_file "botan/eme.h" # # add_file "botan/eme1.cpp" # # add_file "botan/eme_pkcs.cpp" # # add_file "botan/emsa.h" # # add_file "botan/emsa1.cpp" # # add_file "botan/emsa2.cpp" # # add_file "botan/emsa3.cpp" # # add_file "botan/emsa4.cpp" # # add_file "botan/emsa_raw.cpp" # # add_file "botan/eng_base.cpp" # # add_file "botan/engine.cpp" # # add_file "botan/engine.h" # # add_file "botan/enums.h" # # add_file "botan/es_capi.cpp" # # add_file "botan/es_capi.h" # # add_file "botan/es_egd.cpp" # # add_file "botan/es_egd.h" # # add_file "botan/es_file.cpp" # # add_file "botan/es_file.h" # # add_file "botan/exceptn.cpp" # # add_file "botan/exceptn.h" # # add_file "botan/filter.cpp" # # add_file "botan/filter.h" # # add_file "botan/filters.cpp" # # add_file "botan/filters.h" # # add_file "botan/fips140.cpp" # # add_file "botan/fips140.h" # # add_file "botan/fips_rng.cpp" # # add_file "botan/fips_rng.h" # # add_file "botan/fused.cpp" # # add_file "botan/get_algo.cpp" # # add_file "botan/get_enc.cpp" # # add_file "botan/get_pbe.cpp" # # add_file "botan/gzip.cpp" # # add_file "botan/gzip.h" # # add_file "botan/hash_id.cpp" # # add_file "botan/hex.cpp" # # add_file "botan/hex.h" # # add_file "botan/hmac.cpp" # # add_file "botan/hmac.h" # # add_file "botan/if_algo.cpp" # # add_file "botan/if_algo.h" # # add_file "botan/inifile.cpp" # # add_file "botan/init.cpp" # # add_file "botan/init.h" # # add_file "botan/kdf.cpp" # # add_file "botan/kdf.h" # # add_file "botan/keypair.cpp" # # add_file "botan/keypair.h" # # add_file "botan/license.txt" # # add_file "botan/look_add.h" # # add_file "botan/look_pk.cpp" # # add_file "botan/look_pk.h" # # add_file "botan/lookup.cpp" # # add_file "botan/lookup.h" # # add_file "botan/make_prm.cpp" # # add_file "botan/mdx_hash.cpp" # # add_file "botan/mdx_hash.h" # # add_file "botan/mem_ops.h" # # add_file "botan/mem_pool.cpp" # # add_file "botan/mem_pool.h" # # add_file "botan/mgf1.cpp" # # add_file "botan/mgf1.h" # # add_file "botan/mlock.cpp" # # add_file "botan/mod_exp.cpp" # # add_file "botan/mod_exp.h" # # add_file "botan/mode_pad.cpp" # # add_file "botan/mode_pad.h" # # add_file "botan/modebase.cpp" # # add_file "botan/modebase.h" # # add_file "botan/mp_comba.cpp" # # add_file "botan/mp_core.cpp" # # add_file "botan/mp_core.h" # # add_file "botan/mp_fkmul.cpp" # # add_file "botan/mp_madd.h" # # add_file "botan/mp_misc.cpp" # # add_file "botan/mp_mul.cpp" # # add_file "botan/mp_shift.cpp" # # add_file "botan/mp_smul.cpp" # # add_file "botan/mp_types.h" # # add_file "botan/mutex.cpp" # # add_file "botan/mutex.h" # # add_file "botan/numthry.cpp" # # add_file "botan/numthry.h" # # add_file "botan/ofb.cpp" # # add_file "botan/ofb.h" # # add_file "botan/oids.cpp" # # add_file "botan/oids.h" # # add_file "botan/omac.h" # # add_file "botan/par_hash.h" # # add_file "botan/parse.cpp" # # add_file "botan/pbe.h" # # add_file "botan/pbe_pkcs.h" # # add_file "botan/pbes1.cpp" # # add_file "botan/pbes2.cpp" # # add_file "botan/pem.cpp" # # add_file "botan/pem.h" # # add_file "botan/pipe.cpp" # # add_file "botan/pipe.h" # # add_file "botan/pipe_io.cpp" # # add_file "botan/pipe_rw.cpp" # # add_file "botan/pk_algs.cpp" # # add_file "botan/pk_algs.h" # # add_file "botan/pk_core.cpp" # # add_file "botan/pk_core.h" # # add_file "botan/pk_filts.cpp" # # add_file "botan/pk_filts.h" # # add_file "botan/pk_keys.cpp" # # add_file "botan/pk_keys.h" # # add_file "botan/pk_ops.h" # # add_file "botan/pk_util.cpp" # # add_file "botan/pk_util.h" # # add_file "botan/pkcs10.cpp" # # add_file "botan/pkcs10.h" # # add_file "botan/pkcs8.cpp" # # add_file "botan/pkcs8.h" # # add_file "botan/policy.cpp" # # add_file "botan/pow_mod.cpp" # # add_file "botan/prf_ssl3.cpp" # # add_file "botan/prf_tls.cpp" # # add_file "botan/prf_x942.cpp" # # add_file "botan/primes.cpp" # # add_file "botan/pubkey.cpp" # # add_file "botan/pubkey.h" # # add_file "botan/randpool.cpp" # # add_file "botan/randpool.h" # # add_file "botan/readme.txt" # # add_file "botan/reducer.cpp" # # add_file "botan/reducer.h" # # add_file "botan/rng.cpp" # # add_file "botan/rng.h" # # add_file "botan/rsa.cpp" # # add_file "botan/rsa.h" # # add_file "botan/s2k.cpp" # # add_file "botan/s2k.h" # # add_file "botan/secalloc.h" # # add_file "botan/secmem.h" # # add_file "botan/secqueue.cpp" # # add_file "botan/secqueue.h" # # add_file "botan/sha160.cpp" # # add_file "botan/sha160.h" # # add_file "botan/socket.h" # # add_file "botan/symkey.cpp" # # add_file "botan/symkey.h" # # add_file "botan/thanks.txt" # # add_file "botan/timers.cpp" # # add_file "botan/timers.h" # # add_file "botan/types.h" # # add_file "botan/ui.cpp" # # add_file "botan/ui.h" # # add_file "botan/util.cpp" # # add_file "botan/util.h" # # add_file "botan/version.h" # # add_file "botan/x509_ca.cpp" # # add_file "botan/x509_ca.h" # # add_file "botan/x509_crl.cpp" # # add_file "botan/x509_crl.h" # # add_file "botan/x509_key.cpp" # # add_file "botan/x509_key.h" # # add_file "botan/x509_obj.cpp" # # add_file "botan/x509_obj.h" # # add_file "botan/x509cert.cpp" # # add_file "botan/x509cert.h" # # add_file "botan/x509find.cpp" # # add_file "botan/x509opt.cpp" # # add_file "botan/x509self.cpp" # # add_file "botan/x509self.h" # # add_file "botan/x509stor.cpp" # # add_file "botan/x509stor.h" # # add_file "botan/x917_rng.cpp" # # add_file "botan/x917_rng.h" # # add_file "botan/x919_mac.h" # # add_file "fsck.cc" # # add_file "fsck.hh" # # add_file "tests/t_fsck.at" # # patch "AUTHORS" # from [97910e402895c8bbae9ad72fad2e58c9f8965508] # to [48363e3c336bf23f49dcd9cc07f1461ec464695e] # # patch "ChangeLog" # from [f1f875780ef7868880873d47ea2dfa97c297e745] # to [0ecbb568866836a4805b4d61134f72c2b14c064b] # # patch "Makefile.am" # from [b8121dcf5a8aecc511e437ae64e8bdfbba9e880f] # to [1f3cb32fc6408feb79cd788d61e6864e97815160] # # patch "app_state.hh" # from [9cfdb7a5976dc31edda11e99ee74046fdc318469] # to [a239548498beda52f5c4c4488917ef2516cf2fd8] # # patch "botan/aes.cpp" # from [] # to [8135e5fa9b189d5618f67ef27f63b4b16c683ca4] # # patch "botan/aes.h" # from [] # to [244fd78437608f33f3e559d359f8be7abd66c931] # # patch "botan/aes_tab.cpp" # from [] # to [78dcee057d2aa6cf37ca4331a2ce9d499e55ec96] # # patch "botan/algolist.cpp" # from [] # to [e73a701e948afdcb723a29f89e88dbc793764d76] # # patch "botan/algolist.h" # from [] # to [d77a0da036e55d55613326f528ed680d6977bab7] # # patch "botan/allocate.cpp" # from [] # to [bf95f795b13f03947041d16bae44b936d914f30d] # # patch "botan/allocate.h" # from [] # to [f0c3067f73c5cef489b345ab0751b17e5ef07624] # # patch "botan/arc4.cpp" # from [] # to [7ea03bc134ef34a54773c90d4d21d71a9eaa2c18] # # patch "botan/arc4.h" # from [] # to [20156d762201ad8d930a526dbce55fe08ad12996] # # patch "botan/asn1.h" # from [] # to [0673bdaef5291a134595648a953b67dc5d37c442] # # patch "botan/asn1_alg.cpp" # from [] # to [c41db36633e5d356e67540a39230dc95fe36524e] # # patch "botan/asn1_alt.cpp" # from [] # to [003f48d6763514457a190ee5e8753c562223b43d] # # patch "botan/asn1_att.cpp" # from [] # to [175de742c23d2ae762fbe5a4862ae0c131d20392] # # patch "botan/asn1_dn.cpp" # from [] # to [66e58f586ee99e7e0b789250db79320cbae0de16] # # patch "botan/asn1_ext.cpp" # from [] # to [adcded31305574a0c37a44987c27a9c212a81260] # # patch "botan/asn1_ku.cpp" # from [] # to [80baaded8a2bfb051b1b01f74804d51cf9f1a013] # # patch "botan/asn1_obj.h" # from [] # to [197606805a327d6c05f1b98d7181861fc8a6e7ba] # # patch "botan/asn1_oid.cpp" # from [] # to [113696871e0ca992ff1e8c530b77605542b980c9] # # patch "botan/asn1_oid.h" # from [] # to [ff465c835e6a44e73fdabfe10c849e146437a1f3] # # patch "botan/asn1_str.cpp" # from [] # to [56901d327ef5963962c704d9a10a2587e56884a1] # # patch "botan/asn1_tm.cpp" # from [] # to [4a339d34777a8c8f19da139ef0c41d11161dd44d] # # patch "botan/authors.txt" # from [] # to [10798aaadca24ea4ab922825e9b796c5afde6062] # # patch "botan/barrett.cpp" # from [] # to [5c0327d2445b9f3fc066f155674ad2235ca2b64e] # # patch "botan/barrett.h" # from [] # to [8b76f90ed2cd705a5d3a5fb1e57ac9ea2f33b4a2] # # patch "botan/base.cpp" # from [] # to [2d56945dad7cbca306fd1cdfa376297eb796a723] # # patch "botan/base.h" # from [] # to [1fe7fb64e2f2d4cdf9373205ba255ec0296d19ab] # # patch "botan/base64.cpp" # from [] # to [9fe31429403b86d01c267309c04fc90e1e606ff5] # # patch "botan/base64.h" # from [] # to [6903d988dfe5ba1bbc2e82d7c03f3f8ed838ed81] # # patch "botan/base_eng.h" # from [] # to [a1137490aeb1da477c7f827b4cb0c0a4d83be21e] # # patch "botan/basefilt.cpp" # from [] # to [a87e31f5925cc6a1226c1f9e47f206ff7c279d8b] # # patch "botan/basefilt.h" # from [] # to [35b6dbe10c295089d744ebbdef3f98c35b65bfd7] # # patch "botan/ber_code.cpp" # from [] # to [45e75d9d3f7d32d0daf0f692da91cb8c1d4fc326] # # patch "botan/ber_dec.cpp" # from [] # to [b42fae01777b272d26888808e10b95d195801700] # # patch "botan/ber_dec.h" # from [] # to [f0b877d1cfa5d94ec9c0793fc25ac03f24840de8] # # patch "botan/big_base.cpp" # from [] # to [018118b988d580e6ffb34e98d4ccafcd0be4d070] # # patch "botan/big_code.cpp" # from [] # to [50c850ceff3facc002653a9b8d0a1dacfea8c741] # # patch "botan/big_io.cpp" # from [] # to [6a91448edae6ea766cc3159b6ef011acaeabc9ae] # # patch "botan/big_ops2.cpp" # from [] # to [6568718ebd4e38e1e238421efa1be22d37b05db2] # # patch "botan/big_ops3.cpp" # from [] # to [ed3b596d0ac13f3ba549ad1e2849e9966cdf0fea] # # patch "botan/bigint.h" # from [] # to [39ccfdeac610512103d16674c299939e1e693d5a] # # patch "botan/blinding.cpp" # from [] # to [69a1b620f677a22b7c6a55039e964678c3bc2d0a] # # patch "botan/blinding.h" # from [] # to [55ffef0dd36306cf00d35f6f261040c659e2edf7] # # patch "botan/botan.h" # from [] # to [69d369bbb161dadf9db1e224ce7a5b01b97298a4] # # patch "botan/buf_es.cpp" # from [] # to [17ffcafc5f0091775f5ff82361b0e8d211557f0d] # # patch "botan/buf_es.h" # from [] # to [dadb51dc51778193c22232774300054aa6771ff8] # # patch "botan/buf_filt.cpp" # from [] # to [258d2b85a47bc42faf4e50849f125686fe83b2ac] # # patch "botan/buf_filt.h" # from [] # to [0e7534629e985eb81b751339e8c6244007f7c65e] # # patch "botan/cbc.cpp" # from [] # to [ae938d9c8632da302d82fba0a8efab4e609c3885] # # patch "botan/cbc.h" # from [] # to [f741d411a9bd09ee108836e0bf02962ae55cd241] # # patch "botan/certstor.h" # from [] # to [7f5bbeb13d876da9b0905f252110e70250f25289] # # patch "botan/certstore.cpp" # from [] # to [12cddfbff8d0ebf1ddf323198f2381992b527b80] # # patch "botan/cfb.cpp" # from [] # to [e33d8760634d2b5e10329e0c34b5cebe72848904] # # patch "botan/cfb.h" # from [] # to [9b9f3a3ce4094e6f968d12cf0d41bd579219b900] # # patch "botan/charset.cpp" # from [] # to [fb06b37e3cc3dd2f01c30901397d6417bde0a91d] # # patch "botan/conf.cpp" # from [] # to [643f2ea2ddb23e57d0dc3b190c2c9931d4a1fc9c] # # patch "botan/conf.h" # from [] # to [0b602b8e2b927d74ec28d6d87a584aa3e31195ef] # # patch "botan/config.h" # from [] # to [985b707216c13e7cb2684c869166c4dc4e007a45] # # patch "botan/crc32.cpp" # from [] # to [53cbb50cd0477189162fd30c87167042dceeac44] # # patch "botan/crc32.h" # from [] # to [85099a7b83816dc20cb891c999527074187f1ac1] # # patch "botan/crl_ent.cpp" # from [] # to [54b739d37d71f1abcddeb944a58cbee0fa632a84] # # patch "botan/crl_ent.h" # from [] # to [0539e983d16efda8ee76c3fa87b285e774f0b391] # # patch "botan/ctr.cpp" # from [] # to [31a49ab9c99c151565fa8f7298586f342baf7afe] # # patch "botan/ctr.h" # from [] # to [e9b82176a17a126b51e9baab8be858f80c6ca3f6] # # patch "botan/cts.cpp" # from [] # to [0af0fd46dc6c5bb65af0189ef9d5e03bf593df39] # # patch "botan/cts.h" # from [] # to [4c9a0ee6740a624bbf39533f44f24f37c7f0a302] # # patch "botan/data_snk.cpp" # from [] # to [df4b2c5670fe2467986a49ff6a40e8fe836e9ae7] # # patch "botan/data_snk.h" # from [] # to [cb2454f0182f6416729cb5a75279b6a84812be16] # # patch "botan/data_src.cpp" # from [] # to [dfb3403ae7827354d08fd1eb812b0d0441033471] # # patch "botan/data_src.h" # from [] # to [0e7c72b15f861375f65d44b837e24809fb5246cb] # # patch "botan/def_eng.cpp" # from [] # to [036ea54c991b78627bbb43cc80e731f9c8ee2ee6] # # patch "botan/def_eng.h" # from [] # to [a4906d5dd169dc71c5f35111ebe9e7161bebfa16] # # patch "botan/def_ops.cpp" # from [] # to [ca3801883a7902957cded598081a5761aaa10e79] # # patch "botan/defalloc.cpp" # from [] # to [e330d915e67e2b1ff2ea1e01b6f7dc21c752f511] # # patch "botan/defalloc.h" # from [] # to [beda55c363ee2fd4ed5b50d654372a0dd40bf222] # # patch "botan/der_code.cpp" # from [] # to [906a1062209a1f6ecb16ee64c69aa2f653ca9c3e] # # patch "botan/der_enc.cpp" # from [] # to [ac9170917e29853420f5df76943c00eb6df150ea] # # patch "botan/der_enc.h" # from [] # to [a2ddf690cbe1290e24a38b8cc24232b25e48e6a3] # # patch "botan/dh.cpp" # from [] # to [7410d18e0689cf0b88fcd629377532c953fb9372] # # patch "botan/dh.h" # from [] # to [82659d1abc7e35ddb1462a3ff64d26066a17c8a5] # # patch "botan/divide.cpp" # from [] # to [272b0e327dd778b55e36e54e41a6552e1c0c56dd] # # patch "botan/dl_algo.cpp" # from [] # to [06b5b14b241a3dcf402ac8b86446e58dcd762560] # # patch "botan/dl_algo.h" # from [] # to [96e5c93c3d952b29f368ba26ca216bd7781e6675] # # patch "botan/dl_get.cpp" # from [] # to [b01e24eaba2bf8d06c6566f0cb76f8be72c40c77] # # patch "botan/dl_group.cpp" # from [] # to [eb98c6c708e299d70dae4ad614828345ce036a74] # # patch "botan/dl_param.cpp" # from [] # to [2a49018926bb9e393705a2b7c9202af9342fae15] # # patch "botan/dl_param.h" # from [] # to [245ee588426a4fbee58bf4834ae9c373ffcacf32] # # patch "botan/dlies.cpp" # from [] # to [d803e4b7eb0b31f497aac7b06223e7aa28ede268] # # patch "botan/dlies.h" # from [] # to [8cabc3fab297e1d9ffecfd0fec371a3546dbf4f8] # # patch "botan/eax.cpp" # from [] # to [65ab636998b9d9b96d5e90209dfcbc97c0d687a7] # # patch "botan/eax.h" # from [] # to [d1b07e0ba2e6ce2de493b5cf387fb66464f4688a] # # patch "botan/ecb.cpp" # from [] # to [a75694b9df00cbc3ee19e07f95dd42fb53e4598f] # # patch "botan/ecb.h" # from [] # to [737e78fd8af5c8f26487aa2e6e94deef2aedbdcd] # # patch "botan/eme.h" # from [] # to [51b86440d4403db028c50548757795fe49a2192e] # # patch "botan/eme1.cpp" # from [] # to [3c08f892e78d4b3093a3e35cb7351f2b47766e47] # # patch "botan/eme_pkcs.cpp" # from [] # to [dcc6a4ae10f3bc1d50d284cc4285fdf84bc7cad3] # # patch "botan/emsa.h" # from [] # to [5e8b0377da8b2f6d7ce03df9d189498dccce53a2] # # patch "botan/emsa1.cpp" # from [] # to [cdc6b0242927da271f6488eb39502eb36eae3fa4] # # patch "botan/emsa2.cpp" # from [] # to [fae5e6b530c838fccebeac5b6d419efafe0597f1] # # patch "botan/emsa3.cpp" # from [] # to [747190a9e3a8802dd7aefb60b87e6935903fe844] # # patch "botan/emsa4.cpp" # from [] # to [fb48cbf028544c50bdbb6c4f3df82846a576d31f] # # patch "botan/emsa_raw.cpp" # from [] # to [4856d228aa6a7ea5367a91559eae933c5ca3f281] # # patch "botan/eng_base.cpp" # from [] # to [c21bf7a9a3b1e3da0f91db105a4d02d10d574e0b] # # patch "botan/engine.cpp" # from [] # to [516153822616553bed646431168c348713de1e93] # # patch "botan/engine.h" # from [] # to [547b4edca4ac9df32d5121c0b0b5e58d5fbba518] # # patch "botan/enums.h" # from [] # to [8d70f172c1b79d03cbc0d4126d1ae56555207336] # # patch "botan/es_capi.cpp" # from [] # to [e42afd863ee6de903cbb45029d513d15abd05d1c] # # patch "botan/es_capi.h" # from [] # to [9a7ef5ab05ace7647772a20baa3fb803f9d97249] # # patch "botan/es_egd.cpp" # from [] # to [df8fdcbaeb086449cc8387bb62760e7c20178c5c] # # patch "botan/es_egd.h" # from [] # to [5897aea48effee9ea35a1c21a681466db5dbef7c] # # patch "botan/es_file.cpp" # from [] # to [b9c1a6b289f2e79494d77df5fae3f4242d75c1d3] # # patch "botan/es_file.h" # from [] # to [83027d4b6bc201ef272309df3697e43bc846a381] # # patch "botan/exceptn.cpp" # from [] # to [8f5ca9fc666267df72fccd96fc851fdcb7b123f1] # # patch "botan/exceptn.h" # from [] # to [48d813b9a3ca6c896e8cd873cf2491ada522973c] # # patch "botan/filter.cpp" # from [] # to [3506db191bc2d7eaaa67e4e1666add6c3d23a19c] # # patch "botan/filter.h" # from [] # to [d60e7a9d3900ba32b4e2856df6b441007d010138] # # patch "botan/filters.cpp" # from [] # to [ad14e0a2e1639d623b45a8ad63b812945297987a] # # patch "botan/filters.h" # from [] # to [67ed0a521e02165d787c81efee085863b624105e] # # patch "botan/fips140.cpp" # from [] # to [e6fc1426744e58b90917f77c2863627b6bfe3e95] # # patch "botan/fips140.h" # from [] # to [f887fa80632ca747a142f383f8c0a9f4ce6b3f75] # # patch "botan/fips_rng.cpp" # from [] # to [305b3d093136ae275b7a5c667e3c96d860fe5efc] # # patch "botan/fips_rng.h" # from [] # to [45a4189cb973451fbc27a310e9666fc66eec983d] # # patch "botan/fused.cpp" # from [] # to [6fb7c8ea89ea577cf638ca0829f3161261470d8c] # # patch "botan/get_algo.cpp" # from [] # to [fa25847dacdd675514855ff915204e6d9ead8dfa] # # patch "botan/get_enc.cpp" # from [] # to [b0e587e9e8289d9b9ad153491d81f2c81c14a3ef] # # patch "botan/get_pbe.cpp" # from [] # to [cba554a352ad0c15f4da112f89e6069a723d5de2] # # patch "botan/gzip.cpp" # from [] # to [fb3d19b654bb5d8183961396f8f65ee3e3c35134] # # patch "botan/gzip.h" # from [] # to [01488d72ebff8a76915a32fb7bcdbb7af91eb101] # # patch "botan/hash_id.cpp" # from [] # to [41540ab3948c994cfc3f59d5a0a42075779a33ff] # # patch "botan/hex.cpp" # from [] # to [98bbd41c4609c6b02b7af53f09b7e690c4c967be] # # patch "botan/hex.h" # from [] # to [2cfc0e0f5f5a7e368f30225714a3254a362108ed] # # patch "botan/hmac.cpp" # from [] # to [de1313f2eb1b0aa55b39a7b2990682c78f9c9662] # # patch "botan/hmac.h" # from [] # to [2e2149c3036fe4f61e4959787e17d000ec01472d] # # patch "botan/if_algo.cpp" # from [] # to [8ba8e73da35f455f2d33c5364bb8ec50a335e1a9] # # patch "botan/if_algo.h" # from [] # to [4d4b55bbc30d46ede166f16c49a8205772dedcfc] # # patch "botan/inifile.cpp" # from [] # to [93c083a2c23c7fa9594cbfa8e753bba843abd805] # # patch "botan/init.cpp" # from [] # to [fe867ad3ec390b9dfcf9d03f9f3a92a2844fd1bf] # # patch "botan/init.h" # from [] # to [ef58b0990e2ff7abf148e2983417b4696c69872f] # # patch "botan/kdf.cpp" # from [] # to [7a1872d488218b86b88751f7925349d1771483dd] # # patch "botan/kdf.h" # from [] # to [ce2bf9dca868ce3648fbd60f0c89dd41dda8eccb] # # patch "botan/keypair.cpp" # from [] # to [c2ba6d27c702e602ebc5c19401b06a63acd1e1ad] # # patch "botan/keypair.h" # from [] # to [8f3a5a2a87301f0597153df0255d190484036790] # # patch "botan/license.txt" # from [] # to [cf2701bb0aafa9d7d4f52f8f044ad6879cdc862e] # # patch "botan/look_add.h" # from [] # to [ea5876a5bbbe2115a1b85a26f89a91a9c91f4be9] # # patch "botan/look_pk.cpp" # from [] # to [46272ca274e843f3ffbb455a781cc4206cca2551] # # patch "botan/look_pk.h" # from [] # to [f80d5fba4ca6ae87969224851151d9dd56c68d9c] # # patch "botan/lookup.cpp" # from [] # to [b7017306350e0d5cec1bf29fa7aae5fc1476aa14] # # patch "botan/lookup.h" # from [] # to [fc8a5e763db679996fc7bbe67259b70b3fb65c72] # # patch "botan/make_prm.cpp" # from [] # to [38f0b945a62ef720897c2d0641ef1c30b22850cf] # # patch "botan/mdx_hash.cpp" # from [] # to [60980f2b531f0ccc6d9f817a5df85dd30f36724e] # # patch "botan/mdx_hash.h" # from [] # to [cf686de334af142d0a4bead6ffd6fdb6f7b61eb8] # # patch "botan/mem_ops.h" # from [] # to [f5603c43d5c102fa371bdf63e232e6006dc3cecc] # # patch "botan/mem_pool.cpp" # from [] # to [943ebcf01580253115bc2f3e1088791371a55c4d] # # patch "botan/mem_pool.h" # from [] # to [71b41bee14798c742c2a6977bd00764f6b31f160] # # patch "botan/mgf1.cpp" # from [] # to [fdb622c050a16e39088b0a2b5d29e03b732601ce] # # patch "botan/mgf1.h" # from [] # to [128d53c1a67b591b96f6c4a5044da775cc4eb416] # # patch "botan/mlock.cpp" # from [] # to [3010066a99142f353ecdc582c1a18d5bac09dd3d] # # patch "botan/mod_exp.cpp" # from [] # to [1149f9d2c943c0956b769ac266b0d29e9c98f188] # # patch "botan/mod_exp.h" # from [] # to [18c6c30f361b8693f2f4ee33e2b2a597972564fb] # # patch "botan/mode_pad.cpp" # from [] # to [fbcf81f6972834b9a58fba4bbc462feaac03d290] # # patch "botan/mode_pad.h" # from [] # to [bb98613742d08ce0d62663431409f83a2e94ad85] # # patch "botan/modebase.cpp" # from [] # to [441199d5d032597f222e399c80da05c0466e770d] # # patch "botan/modebase.h" # from [] # to [34f3886367213a4a120d1b2bab370ecc9991b203] # # patch "botan/mp_comba.cpp" # from [] # to [cd4bd559010fca3e8f6decfd45ce6801771bc2cd] # # patch "botan/mp_core.cpp" # from [] # to [422451560f3daa8f8cd665dffcfd63d40edda6f3] # # patch "botan/mp_core.h" # from [] # to [1792183f9a720f9fd33838b76eda4ae1515b2f6a] # # patch "botan/mp_fkmul.cpp" # from [] # to [9b24a4c785d41a51a4e6326c8c3f6453c1a34fd8] # # patch "botan/mp_madd.h" # from [] # to [91d7732e96d3a7e6da267164c1984091fb567180] # # patch "botan/mp_misc.cpp" # from [] # to [22d22eba1424da339cf5b710ea421035819a12ca] # # patch "botan/mp_mul.cpp" # from [] # to [6f4b0d753bc894dc0b4a0795645ae560cfc07132] # # patch "botan/mp_shift.cpp" # from [] # to [406513cc6422b5f25d4fd42240dcc6c618f7be64] # # patch "botan/mp_smul.cpp" # from [] # to [ed5ffd208b8b7fa3dc8487fce5f16290a1ecd6f7] # # patch "botan/mp_types.h" # from [] # to [627e3b785902f58ca71f7cb2321b36f0901b090b] # # patch "botan/mutex.cpp" # from [] # to [7ac3c75bf20f6148ac35a8ca8725252dceaf76c1] # # patch "botan/mutex.h" # from [] # to [edfbdfa03538e369e29e72532faa2f2e6eacc55e] # # patch "botan/numthry.cpp" # from [] # to [565ae305cf2ac5ca822796a7527b329403b9204b] # # patch "botan/numthry.h" # from [] # to [17458fbabc1602802e514147f7bcebee4414647e] # # patch "botan/ofb.cpp" # from [] # to [80169c91ae291656e6c4eeec82c3a399b18f09f2] # # patch "botan/ofb.h" # from [] # to [8120445492ab6d9449b761d5005c1de676dffce6] # # patch "botan/oids.cpp" # from [] # to [1a0baccbffdd0f231320d6e554f58a177c18fce8] # # patch "botan/oids.h" # from [] # to [4875b136924adcd55cbb4d8ba4c0ddc784dc3d43] # # patch "botan/omac.h" # from [] # to [999a56ae665d31f7f616b5f6e014cb76d1526f58] # # patch "botan/par_hash.h" # from [] # to [d8401812eec5c2b7e4b60f77f8493a163d178fa5] # # patch "botan/parse.cpp" # from [] # to [a3def2f20cd11724087c05da4dcc46a4a383b142] # # patch "botan/pbe.h" # from [] # to [4993ed6aa4c679740ac5a3003664c720443d44b4] # # patch "botan/pbe_pkcs.h" # from [] # to [47e6d844b94e58ac325f6de110c6565398a3c917] # # patch "botan/pbes1.cpp" # from [] # to [4f8d05c302729c7821e4b40a3076c3fc08c9f26b] # # patch "botan/pbes2.cpp" # from [] # to [68bfe2135c3a4fe2ca4eeb5c83ed61e2368f8ccf] # # patch "botan/pem.cpp" # from [] # to [b72ae3b0a1a422b736f21fc5605d3b4d1591c135] # # patch "botan/pem.h" # from [] # to [bc1422cbd42a4028333a569b150f1ceda195fec4] # # patch "botan/pipe.cpp" # from [] # to [d9c837aa093bfb230cf5c9f9b3978b5bd5bdd0c7] # # patch "botan/pipe.h" # from [] # to [04cb9c849abc6a94e396870f27330ed23b262d31] # # patch "botan/pipe_io.cpp" # from [] # to [974d2e5f91be38025de9db7f01c4fe535facc620] # # patch "botan/pipe_rw.cpp" # from [] # to [59f85107337e39b3418882d48fd2b387405d3d95] # # patch "botan/pk_algs.cpp" # from [] # to [0cf7a8301f09c75bdb93f055fad2f0cd0478e71f] # # patch "botan/pk_algs.h" # from [] # to [68c25007661b1503ea7431ab871bf4a674844c6d] # # patch "botan/pk_core.cpp" # from [] # to [4c3ad70aabe63a760c189fdbfbcad946f73d9d95] # # patch "botan/pk_core.h" # from [] # to [b37fa3da4f807b7f45740b6110d8b4c28cea5fe1] # # patch "botan/pk_filts.cpp" # from [] # to [63d8141f6e0dd0fff341b64327846e33d35c6c00] # # patch "botan/pk_filts.h" # from [] # to [c33f0ad0101684ecdc19fff8126ede12124fafd4] # # patch "botan/pk_keys.cpp" # from [] # to [bb3f3b5fa9ffa98e4949d7f27e1af9d8efbb14cb] # # patch "botan/pk_keys.h" # from [] # to [fa50b78eeda21fc33442d229575c3106b74c5dff] # # patch "botan/pk_ops.h" # from [] # to [d7f762f8ec5b0e52da91ae8864a063bbf94d66d1] # # patch "botan/pk_util.cpp" # from [] # to [2c208fd991b109f7621bc7b99611aae97ae15822] # # patch "botan/pk_util.h" # from [] # to [874530cc97e7f4ca7edc1f540048e6d774a1aee1] # # patch "botan/pkcs10.cpp" # from [] # to [9dd6579c59ce03c6cbd1b11ea2a2db606e9b2206] # # patch "botan/pkcs10.h" # from [] # to [04ea5a06ff5f73eff2964e9e50353caff8bf9a7f] # # patch "botan/pkcs8.cpp" # from [] # to [7ddd271b73aac637d42007f2104781d9f64b924d] # # patch "botan/pkcs8.h" # from [] # to [aa88456c2b2961b74d006b240164b7dbf576b652] # # patch "botan/policy.cpp" # from [] # to [f61a5ad0ee7ddd9ee0fc7e64ae166021f7816051] # # patch "botan/pow_mod.cpp" # from [] # to [59ae9d116647e81fbb6de8f911823034015f16c6] # # patch "botan/prf_ssl3.cpp" # from [] # to [afda5d835c6ef84a6f4691ba6c66b70f4fef3d36] # # patch "botan/prf_tls.cpp" # from [] # to [b28c5a553db6e964d294f0864a767b69d02c6e75] # # patch "botan/prf_x942.cpp" # from [] # to [7b218685f195886dae2ee986c2f55bfdc03fc899] # # patch "botan/primes.cpp" # from [] # to [8c5513f27be0fdb55ffbe22bb3429a4cd582ae4e] # # patch "botan/pubkey.cpp" # from [] # to [dbaf12a2c0e0be641f8d85e9af2c049eb25933cc] # # patch "botan/pubkey.h" # from [] # to [91491173f8aa0f79394f66791b2f73e1db044e0c] # # patch "botan/randpool.cpp" # from [] # to [77d0870820eb8ff049b1c5510f22944d31572331] # # patch "botan/randpool.h" # from [] # to [e485e25942f8e026a1b4c5d309eafba4e58143ae] # # patch "botan/readme.txt" # from [] # to [e6d3de9d3e899187f3701bdc2744619db440b22e] # # patch "botan/reducer.cpp" # from [] # to [ac3ca2c65a244603aa74a72375350d2666605658] # # patch "botan/reducer.h" # from [] # to [782a5a9da892b8ef50c0acd50a7e2f35dc56200b] # # patch "botan/rng.cpp" # from [] # to [61a3c6a4ce80ac0b893ac682e6f3adc26f8468b6] # # patch "botan/rng.h" # from [] # to [ca1a9f356c4e746ef2597ac401325ac746a86221] # # patch "botan/rsa.cpp" # from [] # to [53430bdf7157f135af0e74098840e8e75b75a479] # # patch "botan/rsa.h" # from [] # to [2e6a072ffe722bb6bd472f6b447d20501bcc3cee] # # patch "botan/s2k.cpp" # from [] # to [c9392e2e13421cdbfef0ccab45dc59e9f155c013] # # patch "botan/s2k.h" # from [] # to [68a6ccdce0fede7384124e12fcb442898492a9bf] # # patch "botan/secalloc.h" # from [] # to [b310dff174a674d820a6b76b30e7666f05ff8b64] # # patch "botan/secmem.h" # from [] # to [29935c5b1dc179460e8286f21746322db2ff05bb] # # patch "botan/secqueue.cpp" # from [] # to [5037fd475d246948677e44e2236e800b7c115f92] # # patch "botan/secqueue.h" # from [] # to [106ee36176db91e6152a5b5276980b44aa09b0f1] # # patch "botan/sha160.cpp" # from [] # to [26bf25fdedd24cff075222e44da9f6a98af846c2] # # patch "botan/sha160.h" # from [] # to [e6c428fdf6c80f8c58de85a857e31e27fed82b2d] # # patch "botan/socket.h" # from [] # to [e8849706085cdea44dc8ff3009a2a966965b4b56] # # patch "botan/symkey.cpp" # from [] # to [074224d0aa4368c8291071f47dffe45cb3558206] # # patch "botan/symkey.h" # from [] # to [f33355c7fd13e785fc6f94b21fc0534a4f15b77d] # # patch "botan/thanks.txt" # from [] # to [9971c734b99b04a2b95379e8c1b801d6857d5967] # # patch "botan/timers.cpp" # from [] # to [feff979b666a34d14788555eedf270b7060e592f] # # patch "botan/timers.h" # from [] # to [29ede2e248a818cc5b17b7688a94221259ce38a9] # # patch "botan/types.h" # from [] # to [93238b7a0ee25051c6ddc0ee1a61fcd734978899] # # patch "botan/ui.cpp" # from [] # to [54e27258cd81e065af6b57f9a0acf171ff760760] # # patch "botan/ui.h" # from [] # to [9455f4dce960f0f2b2a05e3e92cc9ba136d31e6e] # # patch "botan/util.cpp" # from [] # to [6a85e690a9d0de8c77fd7c9006a3fcabc5f3c097] # # patch "botan/util.h" # from [] # to [c98b09d26267303db39c6930316ec4bfaa577af2] # # patch "botan/version.h" # from [] # to [0384ce49a78d1f67268676f1b3544a8003fbe283] # # patch "botan/x509_ca.cpp" # from [] # to [8b3275ed1718d77b664a4dac69f9e8df5f25a07e] # # patch "botan/x509_ca.h" # from [] # to [cacda562e7cb5db8e3bc6bb03cb60a30850f9711] # # patch "botan/x509_crl.cpp" # from [] # to [c9aa820103b53c0d8a55aa949fdf8a02e1e8077f] # # patch "botan/x509_crl.h" # from [] # to [17dff45daf11dde3f216958689b06845ed172a4b] # # patch "botan/x509_key.cpp" # from [] # to [f47cf89e09ff326de8136ce3e03f7114eaad2088] # # patch "botan/x509_key.h" # from [] # to [3acac47396c685c507c8a049f0a583dbed5d0a74] # # patch "botan/x509_obj.cpp" # from [] # to [18ea0c22c805e2dc52d92b86a788c1430ffca24d] # # patch "botan/x509_obj.h" # from [] # to [990f87e55fc16c14e143ba9061180486240646ba] # # patch "botan/x509cert.cpp" # from [] # to [2754555bc83253250a1168e7067d288dac9c1905] # # patch "botan/x509cert.h" # from [] # to [3799c01700dffeef0a6d241c656e67f3a4af8dd4] # # patch "botan/x509find.cpp" # from [] # to [fa00cdf310b5642aa8896c693b92db77a66defb9] # # patch "botan/x509opt.cpp" # from [] # to [fba4119a768cdc2f109f87be143a6fe45fbfc914] # # patch "botan/x509self.cpp" # from [] # to [41060ba068e0afb39c729c5b43955d0f8a0bcef9] # # patch "botan/x509self.h" # from [] # to [395ce349b2550df1a44e5a4eb6cf3e98e35a7125] # # patch "botan/x509stor.cpp" # from [] # to [1d4f8428283468c42c16e6dcccd4cd7fc87c9533] # # patch "botan/x509stor.h" # from [] # to [317580b669aabc7ea56d0fa1e68e7d51a0d6e58c] # # patch "botan/x917_rng.cpp" # from [] # to [1025931766017ebe0ad8ebcd50d8a4649f358b14] # # patch "botan/x917_rng.h" # from [] # to [cb25b08a536563d9e5341db6f181530bd79a867a] # # patch "botan/x919_mac.h" # from [] # to [1705fe887e86ebfdade77bbb4486878f72cbfbc5] # # patch "cert.cc" # from [451241f5ac6f41b70211dc92aa500e36688579af] # to [f5dc319c1553610d1246dd94f7397669ab09a77f] # # patch "configure.ac" # from [43ad5babd29ff6f85cb76f7bfbf16b1c0a9e19e9] # to [a6c4321f067e087a721e998c6d701347096aa7be] # # patch "contrib/monotone-notify.pl" # from [7b80bc10043bcd080e0a98742cd49a3c8aa7b8df] # to [7c66c1b5776bdb8b7a325956ded8502434897906] # # patch "database_check.cc" # from [1098ea2b6e2a53449fd89dd6ae815f42d4206cd4] # to [20895ed494e278620fc03bb7f74655b331e25bef] # # patch "file_io.cc" # from [9507250333f6a8542fdfbe4268786ee068e22c16] # to [8beb989df6d6f3318e33f95cd40101b979b68cb7] # # patch "fsck.cc" # from [] # to [a5c158c637d5f51d1f57db0f5908624ecdb7ec08] # # patch "fsck.hh" # from [] # to [68dfc0e92acf9cba9346c0eb67e32a929b930cea] # # patch "keys.cc" # from [a4ccef56d24ee9cda7a009144f5476e3cdcb07d7] # to [ba6a3b2471b851f7114600037312e37a86d73e83] # # patch "keys.hh" # from [f10aaea8dbaf4005a55ec388f278d1bb81d664af] # to [f501788cdc8894ab73f0023b23f92da8adb549ff] # # patch "main.cc" # from [f5427f1b85d11caddbc2732f049250698bbdb6c3] # to [1eff4db78605adee1ef7261417bde7afca407fa6] # # patch "merkle_tree.cc" # from [b0a8cacb8d29ab4a8500c0f2cb34509783dca4c8] # to [b470776b5a443ef073ff29a09ecdc609a23f0213] # # patch "mkstemp.cc" # from [b49b3d62bed1cf26fe36bfcb36c842d70b755081] # to [66cd847d4d881d1477892e19b819ca31024c43af] # # patch "monotone.cc" # from [2419f27fdb3cba77c658c0f4eac4d0b5026e1884] # to [65759f227bc57b92883f785551586f30039721cc] # # patch "netcmd.cc" # from [570582d069ed089439cc7c46c4b1f90098d1045b] # to [eb1a1b795a1a27dfff66d261478fd177796c6a51] # # patch "netsync.cc" # from [04871c9d35e04f3f8ed0d10c6311c643c5f79df1] # to [8790de4edea2bc9f5cda7d35554b5cebc1de065d] # # patch "revision.cc" # from [588fd8a7bcde43a46f0bde1dd1d13e9e77cf25a1] # to [c2d18cfa9db45131465b2d6a7e569c7c96532528] # # patch "schema_migration.cc" # from [f3ff31fcbb6673a7a7847cd669e33eee20d32eae] # to [51b241845c56b3cdb883963c53c4d82778dc9249] # # patch "tests/t_database_check.at" # from [11b64267ef57980019f461ea1acca582d2cb989e] # to [d348fd238d40a27205b242983edb1c13a017b82d] # # patch "tests/t_fsck.at" # from [] # to [dd124d1ba81e72cbef7ce9735035c55b2b18a714] # # patch "tests/t_netsync_unrelated.at" # from [61ec68db6f63d56d79e65780048c527e27e7c737] # to [126a8b13399e2b0adfe1dc8fcebdb82aecc7d138] # # patch "transforms.cc" # from [92b2495dcc4067794d6b3cd58c0f30f865a08a28] # to [012bff62d5ad1dc8bba4123b2b366b02de6fbb75] # # patch "transforms.hh" # from [bb010dc3df990b38ddb900d652d55cc13b4ff423] # to [0886fc260e3989244f914da25c26e8b6ffc8342f] # # patch "unit_tests.cc" # from [230b4227d08bed323a2625f593073427bca9fe9b] # to [b8ad9bacce247d9844c377c822e6c16ccedf9d14] # # patch "unix/inodeprint.cc" # from [ba3f21edca6b9c5461bdc844d9c519b70fc4ad1a] # to [e7b2c3152595841807069e9d335f37536df6de3d] # # patch "work.hh" # from [1e96bd36f787031f743d29cc033bfd1cc1a9c8e2] # to [b379ccc674d25414e6e890a00688c716c51a85fe] # --- AUTHORS +++ AUTHORS @@ -63,15 +63,6 @@ http://www.sqlite.org. -Wei Dai wrote many of the files in cryptopp/*, -though possibly not all of them; the files themselves were assigned to -the public domain, and Wei Dai retains copyright only over the -collective work of the crypto++ library from whence they were -copied. I make no claim to be representing the crypto++ collective -work here; I am merely using several public domain files from it. You -can find the original code at http://www.cryptopp.com. - - The files in idna/* are copies of the core portion of the "GNU libidn" library. Copyright (C) 2002, 2003 Simon Josefsson. They are licensed under the GNU LGPL version 2.1. The original sources for libidn can be @@ -196,6 +187,38 @@ --- +Jack Lloyd wrote the majority of the Botan +library, with contributions as noted in botan/thanks.txt +The library is distributed under a BSD-like license: + +--- + +Copyright (C) 1999-2004 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions, and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + +IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + The files in popt/* are copies of the original popt 1.7 as provided by Debian (their own version number is 1.7-5). According to the README (reproduced as popt/README), it was written by a (former?) RedHat --- ChangeLog +++ ChangeLog @@ -116,6 +116,11 @@ (PNG_FIGURES): Add, constructing in same way as EPS_FIGURES (monotone.html): Use .perlbak workaround so that this works on Win32 +2005-04-11 Matt Johnston + + * unix/inodeprint.cc: use botan for sha1 + * various merge fixups + 2005-04-10 Nathaniel Smith * Makefile.am (BUILT_SOURCES_CLEAN): Add package_revision.txt. @@ -408,6 +413,11 @@ * tests/t_sql_unpack.at: New test. * testsuite.at: Add it. +2005-04-04 Matt Johnston + + * file_io.cc (read_data_stdin): make it use botan + * mkstemp.cc: merge cleanup (missed something up the manual merge) + 2005-04-04 Nathaniel Smith * contrib/ciabot_monotone.py (config): Genericize again, so lazy @@ -738,6 +748,19 @@ 2005-03-25 Matt Johnston + * tests/t_database_check.at: re-encode the manifestX + data so that it doesn't use any fancy gzip features like + filenames (so that the botan parse can handle it). + ( if it should be able to handle it, an additional test + can be added testing it explicitly). + +2005-03-25 Matt Johnston + + * botan/base64.h: Change default break value so that + output is split into 72 col lines. + +2005-03-25 Matt Johnston + * monotone.cc: add short options -r, -b, -k, and -m for --revision, --branch, --key, and --message respectively. * monotone.texi, monotone.1: document them @@ -2226,7 +2249,14 @@ (import_states_by_branch): Add 'revisions' argument. (import_cvs_repo): Add a stage 3 that writes out the revisions accumulated in the 'revisions' vector. + +2005-01-27 Matt Johnston + (compile fixes for Linux/gcc 3.3.4) + * botan/{util.cpp,primes.cpp}: give large constants ULL + suffixes + * botan/{gzip.cpp}: fix type for std::max() comparison + 2005-01-27 graydon hoare * AUTHORS: Mention Georg. @@ -2642,6 +2672,11 @@ informative. (rcs_import): Also add more details to help text. +2005-01-17 Matt Johnston + + * file_io.cc: re-add accidentally removed #include + * botan/gzip.cc: improved comments, removed unused code + 2005-01-17 Nathaniel Smith * diff_patch.cc (normalize_extents): Add missing ')'. @@ -2886,6 +2921,18 @@ function * tests/t_cross.at: update to work with changesets +2005-1-1 Matt Johnston + + * botan/base64.cpp: Include a terminating newline in all cases for + compatibility with cryptopp + +2005-1-1 Matt Johnston + + * keys.cc: fix merge issues propagating 0.16 to net.venge.monotone.botan + * botan/config.h: add it + * botan/{aes,des,dh,dsa,elgamal,lion,lubyrack,nr,rw,openpgp}*: removed + unused files. + 2004-12-30 graydon hoare * constants.cc (netcmd_current_protocol_version): Set to 3. @@ -3764,6 +3811,10 @@ tids being used. (merge_disjoint_analyses): Fix typo (s/a_tmp/b_tmp/) +2004-11-27 Matt Johnston + + * Replaced cryptopp with botan + 2004-11-24 Nathaniel Smith * tests/t_cleanup_empty_dir.at: Shorten name. --- Makefile.am +++ Makefile.am @@ -40,35 +40,49 @@ netxx/probeinfo.h netxx/sockopt.h netxx/stream.h netxx/streambase.h \ netxx/streamserver.h netxx/timeout.h netxx/types.h +BOTAN_SOURCES = \ + botan/aes.cpp botan/aes_tab.cpp botan/algolist.cpp botan/allocate.cpp \ + botan/arc4.cpp botan/asn1_alg.cpp botan/asn1_alt.cpp botan/asn1_att.cpp \ + botan/asn1_dn.cpp botan/asn1_ext.cpp botan/asn1_ku.cpp \ + botan/asn1_oid.cpp botan/asn1_str.cpp botan/asn1_tm.cpp \ + botan/barrett.cpp botan/base.cpp botan/base64.cpp botan/basefilt.cpp \ + botan/ber_code.cpp botan/ber_dec.cpp botan/big_base.cpp \ + botan/big_code.cpp botan/big_io.cpp botan/big_ops2.cpp \ + botan/big_ops3.cpp botan/blinding.cpp botan/buf_es.cpp \ + botan/buf_filt.cpp botan/cbc.cpp botan/certstore.cpp botan/cfb.cpp \ + botan/charset.cpp botan/conf.cpp botan/crc32.cpp botan/crl_ent.cpp \ + botan/ctr.cpp botan/cts.cpp botan/data_snk.cpp botan/data_src.cpp \ + botan/def_eng.cpp botan/def_ops.cpp botan/defalloc.cpp \ + botan/der_code.cpp botan/der_enc.cpp \ + botan/divide.cpp botan/dl_algo.cpp botan/dl_get.cpp \ + botan/dl_group.cpp botan/dl_param.cpp botan/dlies.cpp \ + botan/eax.cpp botan/ecb.cpp botan/eme1.cpp \ + botan/eme_pkcs.cpp botan/emsa1.cpp botan/emsa2.cpp botan/emsa3.cpp \ + botan/emsa4.cpp botan/emsa_raw.cpp botan/eng_base.cpp botan/engine.cpp \ + botan/es_file.cpp botan/exceptn.cpp botan/filter.cpp botan/filters.cpp \ + botan/fips140.cpp botan/fips_rng.cpp botan/fused.cpp botan/get_algo.cpp \ + botan/get_enc.cpp botan/get_pbe.cpp botan/gzip.cpp botan/hash_id.cpp \ + botan/hex.cpp botan/hmac.cpp botan/if_algo.cpp botan/inifile.cpp \ + botan/init.cpp botan/kdf.cpp botan/keypair.cpp botan/look_pk.cpp \ + botan/lookup.cpp botan/make_prm.cpp botan/mdx_hash.cpp \ + botan/mem_pool.cpp botan/mgf1.cpp botan/mlock.cpp botan/mod_exp.cpp \ + botan/mode_pad.cpp botan/modebase.cpp botan/mp_comba.cpp \ + botan/mp_core.cpp botan/mp_fkmul.cpp botan/mp_misc.cpp botan/mp_mul.cpp \ + botan/mp_shift.cpp botan/mp_smul.cpp botan/mutex.cpp \ + botan/numthry.cpp botan/ofb.cpp botan/oids.cpp \ + botan/parse.cpp botan/pbes1.cpp botan/pbes2.cpp botan/pem.cpp \ + botan/pipe.cpp botan/pipe_io.cpp botan/pipe_rw.cpp botan/pk_algs.cpp \ + botan/pk_core.cpp botan/pk_filts.cpp botan/pk_keys.cpp \ + botan/pk_util.cpp botan/pkcs10.cpp botan/pkcs8.cpp botan/policy.cpp \ + botan/pow_mod.cpp botan/prf_ssl3.cpp botan/prf_tls.cpp \ + botan/prf_x942.cpp botan/primes.cpp botan/pubkey.cpp botan/randpool.cpp \ + botan/reducer.cpp botan/rng.cpp botan/rsa.cpp \ + botan/s2k.cpp botan/secqueue.cpp botan/sha160.cpp botan/symkey.cpp \ + botan/timers.cpp botan/ui.cpp botan/util.cpp botan/x509_ca.cpp \ + botan/x509_crl.cpp botan/x509_key.cpp botan/x509_obj.cpp \ + botan/x509cert.cpp botan/x509find.cpp botan/x509opt.cpp \ + botan/x509self.cpp botan/x509stor.cpp botan/x917_rng.cpp -CRYPTOPP_SOURCES = \ - cryptopp/algebra.cpp cryptopp/algparam.cpp cryptopp/arc4.cpp \ - cryptopp/asn.cpp cryptopp/base64.cpp cryptopp/basecode.cpp \ - cryptopp/crc.cpp cryptopp/cryptlib.cpp cryptopp/des.cpp cryptopp/dessp.cpp \ - cryptopp/dll.cpp cryptopp/eprecomp.cpp cryptopp/files.cpp cryptopp/filters.cpp \ - cryptopp/fips140.cpp cryptopp/gzip.cpp cryptopp/hex.cpp cryptopp/hmac.cpp \ - cryptopp/integer.cpp cryptopp/iterhash.cpp cryptopp/misc.cpp \ - cryptopp/modes.cpp cryptopp/mqueue.cpp cryptopp/nbtheory.cpp \ - cryptopp/oaep.cpp cryptopp/osrng.cpp cryptopp/pch.cpp cryptopp/pkcspad.cpp \ - cryptopp/pssr.cpp cryptopp/pubkey.cpp cryptopp/queue.cpp \ - cryptopp/randpool.cpp cryptopp/rng.cpp cryptopp/rsa.cpp cryptopp/sha.cpp \ - cryptopp/strciphr.cpp cryptopp/trdlocal.cpp cryptopp/zdeflate.cpp \ - cryptopp/zinflate.cpp \ - \ - cryptopp/algebra.h cryptopp/algparam.h cryptopp/arc4.h cryptopp/argnames.h \ - cryptopp/asn.h cryptopp/base64.h cryptopp/basecode.h cryptopp/config.h \ - cryptopp/crc.h cryptopp/cryptlib.h cryptopp/des.h cryptopp/dll.h cryptopp/eprecomp.h \ - cryptopp/files.h cryptopp/filters.h cryptopp/fips140.h cryptopp/fltrimpl.h \ - cryptopp/gzip.h cryptopp/hex.h cryptopp/integer.h cryptopp/iterhash.h \ - cryptopp/mdc.h cryptopp/misc.h cryptopp/modarith.h cryptopp/modes.h \ - cryptopp/mqueue.h cryptopp/nbtheory.h cryptopp/oaep.h cryptopp/oids.h \ - cryptopp/osrng.h cryptopp/pch.h cryptopp/pkcspad.h cryptopp/pssr.h \ - cryptopp/pubkey.h cryptopp/queue.h cryptopp/randpool.h cryptopp/rng.h \ - cryptopp/rsa.h cryptopp/secblock.h cryptopp/seckey.h cryptopp/sha.h \ - cryptopp/simple.h cryptopp/smartptr.h cryptopp/stdcpp.h cryptopp/strciphr.h \ - cryptopp/trdlocal.h cryptopp/words.h cryptopp/zdeflate.h \ - cryptopp/zinflate.h cryptopp/hmac.h - BOOST_SANDBOX_SOURCES = \ boost/circular_buffer_adaptor.hpp \ boost/circular_buffer_base.hpp \ @@ -137,7 +151,7 @@ noinst_LIBRARIES = libplatform.a lib3rdparty.a libplatform_a_SOURCES = platform.hh lib3rdparty_a_SOURCES = $(BOOST_SANDBOX_SOURCES) \ - $(CRYPTOPP_SOURCES) \ + $(BOTAN_SOURCES) \ $(IDNA_SOURCES) \ $(POPT_SOURCES) \ $(NETXX_SOURCES) @@ -188,6 +202,8 @@ libplatform_a_SOURCES += $(WIN32_PLATFORM_SOURCES) monotone_LDADD += -lws2_32 -lintl -liconv -liphlpapi unit_tests_LDADD += -lws2_32 -lintl -liconv -liphlpapi + lib3rdparty_a_CPPFLAGS += -DWIN32 + lib3rdparty_a_SOURCES += botan/es_capi.cpp else libplatform_a_SOURCES += $(UNIX_PLATFORM_SOURCES) endif --- app_state.hh +++ app_state.hh @@ -9,6 +9,10 @@ class app_state; class lua_hooks; +#include +#include +#include + #include #include "database.hh" @@ -41,6 +45,18 @@ bool found_working_copy; long depth; + // These are used to cache signers/verifiers (if the hook allows). + // They can't be function-static variables in key.cc, since they must be + // destroyed before the Botan deinitialize() function is called. */ + std::map, + boost::shared_ptr > > signers; + std::map, + boost::shared_ptr > > verifiers; + + void initialize(bool working_copy); + void initialize(std::string const & dir); void allow_working_copy(); void require_working_copy(); void create_working_copy(std::string const & dir); --- botan/aes.cpp +++ botan/aes.cpp @@ -0,0 +1,193 @@ +/************************************************* +* AES Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* AES Encryption * +*************************************************/ +void AES::enc(const byte in[], byte out[]) const + { + u32bit T0, T1, T2, T3, B0, B1, B2, B3; + B0 = TE0[in[ 0] ^ ME[ 0]] ^ TE1[in[ 5] ^ ME[ 5]] ^ + TE2[in[10] ^ ME[10]] ^ TE3[in[15] ^ ME[15]] ^ EK[0]; + B1 = TE0[in[ 4] ^ ME[ 4]] ^ TE1[in[ 9] ^ ME[ 9]] ^ + TE2[in[14] ^ ME[14]] ^ TE3[in[ 3] ^ ME[ 3]] ^ EK[1]; + B2 = TE0[in[ 8] ^ ME[ 8]] ^ TE1[in[13] ^ ME[13]] ^ + TE2[in[ 2] ^ ME[ 2]] ^ TE3[in[ 7] ^ ME[ 7]] ^ EK[2]; + B3 = TE0[in[12] ^ ME[12]] ^ TE1[in[ 1] ^ ME[ 1]] ^ + TE2[in[ 6] ^ ME[ 6]] ^ TE3[in[11] ^ ME[11]] ^ EK[3]; + for(u32bit j = 1; j != ROUNDS - 1; j += 2) + { + T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(1, B1)] ^ + TE2[get_byte(2, B2)] ^ TE3[get_byte(3, B3)] ^ EK[4*j+0]; + T1 = TE0[get_byte(0, B1)] ^ TE1[get_byte(1, B2)] ^ + TE2[get_byte(2, B3)] ^ TE3[get_byte(3, B0)] ^ EK[4*j+1]; + T2 = TE0[get_byte(0, B2)] ^ TE1[get_byte(1, B3)] ^ + TE2[get_byte(2, B0)] ^ TE3[get_byte(3, B1)] ^ EK[4*j+2]; + T3 = TE0[get_byte(0, B3)] ^ TE1[get_byte(1, B0)] ^ + TE2[get_byte(2, B1)] ^ TE3[get_byte(3, B2)] ^ EK[4*j+3]; + B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(1, T1)] ^ + TE2[get_byte(2, T2)] ^ TE3[get_byte(3, T3)] ^ EK[4*j+4]; + B1 = TE0[get_byte(0, T1)] ^ TE1[get_byte(1, T2)] ^ + TE2[get_byte(2, T3)] ^ TE3[get_byte(3, T0)] ^ EK[4*j+5]; + B2 = TE0[get_byte(0, T2)] ^ TE1[get_byte(1, T3)] ^ + TE2[get_byte(2, T0)] ^ TE3[get_byte(3, T1)] ^ EK[4*j+6]; + B3 = TE0[get_byte(0, T3)] ^ TE1[get_byte(1, T0)] ^ + TE2[get_byte(2, T1)] ^ TE3[get_byte(3, T2)] ^ EK[4*j+7]; + } + out[ 0] = SE[get_byte(0, B0)] ^ ME[16]; + out[ 1] = SE[get_byte(1, B1)] ^ ME[17]; + out[ 2] = SE[get_byte(2, B2)] ^ ME[18]; + out[ 3] = SE[get_byte(3, B3)] ^ ME[19]; + out[ 4] = SE[get_byte(0, B1)] ^ ME[20]; + out[ 5] = SE[get_byte(1, B2)] ^ ME[21]; + out[ 6] = SE[get_byte(2, B3)] ^ ME[22]; + out[ 7] = SE[get_byte(3, B0)] ^ ME[23]; + out[ 8] = SE[get_byte(0, B2)] ^ ME[24]; + out[ 9] = SE[get_byte(1, B3)] ^ ME[25]; + out[10] = SE[get_byte(2, B0)] ^ ME[26]; + out[11] = SE[get_byte(3, B1)] ^ ME[27]; + out[12] = SE[get_byte(0, B3)] ^ ME[28]; + out[13] = SE[get_byte(1, B0)] ^ ME[29]; + out[14] = SE[get_byte(2, B1)] ^ ME[30]; + out[15] = SE[get_byte(3, B2)] ^ ME[31]; + } + +/************************************************* +* AES Decryption * +*************************************************/ +void AES::dec(const byte in[], byte out[]) const + { + u32bit T0, T1, T2, T3, B0, B1, B2, B3; + B0 = TD0[in[ 0] ^ MD[ 0]] ^ TD1[in[13] ^ MD[13]] ^ + TD2[in[10] ^ MD[10]] ^ TD3[in[ 7] ^ MD[ 7]] ^ DK[0]; + B1 = TD0[in[ 4] ^ MD[ 4]] ^ TD1[in[ 1] ^ MD[ 1]] ^ + TD2[in[14] ^ MD[14]] ^ TD3[in[11] ^ MD[11]] ^ DK[1]; + B2 = TD0[in[ 8] ^ MD[ 8]] ^ TD1[in[ 5] ^ MD[ 5]] ^ + TD2[in[ 2] ^ MD[ 2]] ^ TD3[in[15] ^ MD[15]] ^ DK[2]; + B3 = TD0[in[12] ^ MD[12]] ^ TD1[in[ 9] ^ MD[ 9]] ^ + TD2[in[ 6] ^ MD[ 6]] ^ TD3[in[ 3] ^ MD[ 3]] ^ DK[3]; + for(u32bit j = 1; j != ROUNDS - 1; j += 2) + { + T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(1, B3)] ^ + TD2[get_byte(2, B2)] ^ TD3[get_byte(3, B1)] ^ DK[4*j+0]; + T1 = TD0[get_byte(0, B1)] ^ TD1[get_byte(1, B0)] ^ + TD2[get_byte(2, B3)] ^ TD3[get_byte(3, B2)] ^ DK[4*j+1]; + T2 = TD0[get_byte(0, B2)] ^ TD1[get_byte(1, B1)] ^ + TD2[get_byte(2, B0)] ^ TD3[get_byte(3, B3)] ^ DK[4*j+2]; + T3 = TD0[get_byte(0, B3)] ^ TD1[get_byte(1, B2)] ^ + TD2[get_byte(2, B1)] ^ TD3[get_byte(3, B0)] ^ DK[4*j+3]; + B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(1, T3)] ^ + TD2[get_byte(2, T2)] ^ TD3[get_byte(3, T1)] ^ DK[4*j+4]; + B1 = TD0[get_byte(0, T1)] ^ TD1[get_byte(1, T0)] ^ + TD2[get_byte(2, T3)] ^ TD3[get_byte(3, T2)] ^ DK[4*j+5]; + B2 = TD0[get_byte(0, T2)] ^ TD1[get_byte(1, T1)] ^ + TD2[get_byte(2, T0)] ^ TD3[get_byte(3, T3)] ^ DK[4*j+6]; + B3 = TD0[get_byte(0, T3)] ^ TD1[get_byte(1, T2)] ^ + TD2[get_byte(2, T1)] ^ TD3[get_byte(3, T0)] ^ DK[4*j+7]; + } + out[ 0] = SD[get_byte(0, B0)] ^ MD[16]; + out[ 1] = SD[get_byte(1, B3)] ^ MD[17]; + out[ 2] = SD[get_byte(2, B2)] ^ MD[18]; + out[ 3] = SD[get_byte(3, B1)] ^ MD[19]; + out[ 4] = SD[get_byte(0, B1)] ^ MD[20]; + out[ 5] = SD[get_byte(1, B0)] ^ MD[21]; + out[ 6] = SD[get_byte(2, B3)] ^ MD[22]; + out[ 7] = SD[get_byte(3, B2)] ^ MD[23]; + out[ 8] = SD[get_byte(0, B2)] ^ MD[24]; + out[ 9] = SD[get_byte(1, B1)] ^ MD[25]; + out[10] = SD[get_byte(2, B0)] ^ MD[26]; + out[11] = SD[get_byte(3, B3)] ^ MD[27]; + out[12] = SD[get_byte(0, B3)] ^ MD[28]; + out[13] = SD[get_byte(1, B2)] ^ MD[29]; + out[14] = SD[get_byte(2, B1)] ^ MD[30]; + out[15] = SD[get_byte(3, B0)] ^ MD[31]; + } + +/************************************************* +* AES Key Schedule * +*************************************************/ +void AES::key(const byte key[], u32bit length) + { + static const u32bit RC[10] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, + 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; + ROUNDS = (length / 4) + 6; + + SecureBuffer XEK, XDK; + + const u32bit X = length / 4; + for(u32bit j = 0; j != X; j++) + XEK[j] = make_u32bit(key[4*j], key[4*j+1], key[4*j+2], key[4*j+3]); + for(u32bit j = X; j < 4*(ROUNDS+1); j += X) + { + XEK[j] = XEK[j-X] ^ S(rotate_left(XEK[j-1], 8)) ^ RC[(j-X)/X]; + for(u32bit k = 1; k != X; k++) + { + if(X == 8 && k == 4) + XEK[j+k] = XEK[j+k-X] ^ S(XEK[j+k-1]); + else + XEK[j+k] = XEK[j+k-X] ^ XEK[j+k-1]; + } + } + + for(u32bit j = 0; j != 4*(ROUNDS+1); j += 4) + { + XDK[j ] = XEK[4*ROUNDS-j ]; + XDK[j+1] = XEK[4*ROUNDS-j+1]; + XDK[j+2] = XEK[4*ROUNDS-j+2]; + XDK[j+3] = XEK[4*ROUNDS-j+3]; + } + for(u32bit j = 4; j != length + 24; j++) + XDK[j] = TD0[SE[get_byte(0, XDK[j])]] ^ TD1[SE[get_byte(1, XDK[j])]] ^ + TD2[SE[get_byte(2, XDK[j])]] ^ TD3[SE[get_byte(3, XDK[j])]]; + + for(u32bit j = 0; j != 4; j++) + for(u32bit k = 0; k != 4; k++) + { + ME[4*j+k ] = get_byte(k, XEK[j]); + ME[4*j+k+16] = get_byte(k, XEK[j+4*ROUNDS]); + MD[4*j+k ] = get_byte(k, XDK[j]); + MD[4*j+k+16] = get_byte(k, XEK[j]); + } + + EK.copy(XEK + 4, length + 20); + DK.copy(XDK + 4, length + 20); + } + +/************************************************* +* AES Byte Substitution * +*************************************************/ +u32bit AES::S(u32bit input) + { + return make_u32bit(SE[get_byte(0, input)], SE[get_byte(1, input)], + SE[get_byte(2, input)], SE[get_byte(3, input)]); + } + +/************************************************* +* AES Constructor * +*************************************************/ +AES::AES(u32bit key_size) : BlockCipher(16, key_size) + { + if(key_size != 16 && key_size != 24 && key_size != 32) + throw Invalid_Argument("AES: Bad key size " + to_string(key_size)); + ROUNDS = (key_size / 4) + 6; + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void AES::clear() throw() + { + EK.clear(); + DK.clear(); + ME.clear(); + MD.clear(); + } + +} --- botan/aes.h +++ botan/aes.h @@ -0,0 +1,72 @@ +/************************************************* +* AES Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_AES_H__ +#define BOTAN_AES_H__ + +#include + +namespace Botan { + +/************************************************* +* AES * +*************************************************/ +class AES : public BlockCipher + { + public: + void clear() throw(); + std::string name() const { return "AES"; } + BlockCipher* clone() const { return new AES; } + AES() : BlockCipher(16, 16, 32, 8) { ROUNDS = 14; } + AES(u32bit); + private: + void enc(const byte[], byte[]) const; + void dec(const byte[], byte[]) const; + void key(const byte[], u32bit); + static u32bit S(u32bit); + static const byte SE[256], SD[256]; + static const u32bit TE0[256], TE1[256], TE2[256], TE3[256], + TD0[256], TD1[256], TD2[256], TD3[256]; + SecureBuffer EK, DK; + SecureBuffer ME, MD; + u32bit ROUNDS; + }; + +/************************************************* +* AES-128 * +*************************************************/ +class AES_128 : public AES + { + public: + std::string name() const { return "AES-128"; } + BlockCipher* clone() const { return new AES_128; } + AES_128() : AES(16) {} + }; + +/************************************************* +* AES-192 * +*************************************************/ +class AES_192 : public AES + { + public: + std::string name() const { return "AES-192"; } + BlockCipher* clone() const { return new AES_192; } + AES_192() : AES(24) {} + }; + +/************************************************* +* AES-256 * +*************************************************/ +class AES_256 : public AES + { + public: + std::string name() const { return "AES-256"; } + BlockCipher* clone() const { return new AES_256; } + AES_256() : AES(32) {} + }; + +} + +#endif --- botan/aes_tab.cpp +++ botan/aes_tab.cpp @@ -0,0 +1,414 @@ +/************************************************* +* S-Box and Diffusion Tables for AES * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +const byte AES::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 AES::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 AES::TE0[256] = { +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 }; + +const u32bit AES::TE1[256] = { +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 }; + +const u32bit AES::TE2[256] = { +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 }; + +const u32bit AES::TE3[256] = { +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 AES::TD0[256] = { +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 }; + +const u32bit AES::TD1[256] = { +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 }; + +const u32bit AES::TD2[256] = { +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 }; + +const u32bit AES::TD3[256] = { +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 }; + +} --- botan/algolist.cpp +++ botan/algolist.cpp @@ -0,0 +1,162 @@ +/************************************************* +* Algorithms List Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +#include + +#include + +#include +#include + +#include + +#include + +namespace Botan { + +namespace Algolist { + +/************************************************* +* Some macros to simplify control flow * +*************************************************/ +#define HANDLE_TYPE_NO_ARGS(NAME, TYPE) \ + if(algo_name == NAME) \ + { \ + if(name.size() == 1) \ + return new TYPE; \ + throw Invalid_Algorithm_Name(algo_spec); \ + } + +#define HANDLE_TYPE_ONE_U32BIT(NAME, TYPE, DEFAULT) \ + if(algo_name == NAME) \ + { \ + if(name.size() == 1) \ + return new TYPE(DEFAULT); \ + if(name.size() == 2) \ + return new TYPE(to_u32bit(name[1])); \ + throw Invalid_Algorithm_Name(algo_spec); \ + } + +#define HANDLE_TYPE_TWO_U32BIT(NAME, TYPE, DEFAULT) \ + if(algo_name == NAME) \ + { \ + if(name.size() == 1) \ + return new TYPE(DEFAULT); \ + if(name.size() == 2) \ + return new TYPE(to_u32bit(name[1])); \ + if(name.size() == 3) \ + return new TYPE(to_u32bit(name[1]), to_u32bit(name[2])); \ + throw Invalid_Algorithm_Name(algo_spec); \ + } + +#define HANDLE_TYPE_ONE_STRING(NAME, TYPE) \ + if(algo_name == NAME) \ + { \ + if(name.size() == 2) \ + return new TYPE(name[1]); \ + throw Invalid_Algorithm_Name(algo_spec); \ + } + +/************************************************* +* Attempt to get a block cipher object * +*************************************************/ +BlockCipher* get_block_cipher(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + if(name.size() == 0) + return 0; + const std::string algo_name = deref_alias(name[0]); + + HANDLE_TYPE_NO_ARGS("AES", AES); + HANDLE_TYPE_NO_ARGS("AES-128", AES_128); + HANDLE_TYPE_NO_ARGS("AES-192", AES_192); + HANDLE_TYPE_NO_ARGS("AES-256", AES_256); + + return 0; + } + +/************************************************* +* Attempt to get a stream cipher object * +*************************************************/ +StreamCipher* get_stream_cipher(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + if(name.size() == 0) + return 0; + const std::string algo_name = deref_alias(name[0]); + + HANDLE_TYPE_ONE_U32BIT("ARC4", ARC4, 0); + HANDLE_TYPE_ONE_U32BIT("RC4_drop", ARC4, 768); + + return 0; + } + +/************************************************* +* Attempt to get a hash function object * +*************************************************/ +HashFunction* get_hash(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + if(name.size() == 0) + return 0; + const std::string algo_name = deref_alias(name[0]); + + HANDLE_TYPE_NO_ARGS("CRC32", CRC32); + HANDLE_TYPE_NO_ARGS("SHA-160", SHA_160); + + return 0; + } + +/************************************************* +* Attempt to get an authentication code object * +*************************************************/ +MessageAuthenticationCode* get_mac(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + if(name.size() == 0) + return 0; + const std::string algo_name = deref_alias(name[0]); + + HANDLE_TYPE_ONE_STRING("HMAC", HMAC); + + return 0; + } + +/************************************************* +* Attempt to get a string to key object * +*************************************************/ +S2K* get_s2k(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + if(name.size() == 0) + return 0; + const std::string algo_name = deref_alias(name[0]); + + return 0; + } + +/************************************************* +* Attempt to get a block cipher padding method * +*************************************************/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + if(name.size() == 0) + return 0; + const std::string algo_name = deref_alias(name[0]); + + HANDLE_TYPE_NO_ARGS("PKCS7", PKCS7_Padding); + HANDLE_TYPE_NO_ARGS("OneAndZeros", OneAndZeros_Padding); + HANDLE_TYPE_NO_ARGS("X9.23", ANSI_X923_Padding); + HANDLE_TYPE_NO_ARGS("NoPadding", Null_Padding); + + return 0; + } + +} + +} --- botan/algolist.h +++ botan/algolist.h @@ -0,0 +1,31 @@ +/************************************************* +* Algorithm Lookup Table Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ALGOLIST_H__ +#define BOTAN_ALGOLIST_H__ + +#include +#include +#include + +namespace Botan { + +namespace Algolist { + +/************************************************* +* Lookup an algorithm in the table * +*************************************************/ +BlockCipher* get_block_cipher(const std::string&); +StreamCipher* get_stream_cipher(const std::string&); +HashFunction* get_hash(const std::string&); +MessageAuthenticationCode* get_mac(const std::string&); +S2K* get_s2k(const std::string&); +BlockCipherModePaddingMethod* get_bc_pad(const std::string&); + +} + +} + +#endif --- botan/allocate.cpp +++ botan/allocate.cpp @@ -0,0 +1,162 @@ +/************************************************* +* Allocator Factory Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* A factory for creating Allocators * +*************************************************/ +class AllocatorFactory + { + public: + Allocator* get(const std::string&) const; + void add(const std::string&, Allocator*); + std::string set_default_allocator(const std::string&); + + AllocatorFactory() { factory_lock = get_mutex(); } + ~AllocatorFactory(); + private: + std::map alloc; + std::string default_allocator; + Mutex* factory_lock; + }; + +/************************************************* +* Get an allocator from the factory * +*************************************************/ +Allocator* AllocatorFactory::get(const std::string& type) const + { + Mutex_Holder lock(factory_lock); + + std::map::const_iterator iter; + if(type == "default") iter = alloc.find(default_allocator); + else iter = alloc.find(type); + + if(iter == alloc.end()) + return 0; + return iter->second; + } + +/************************************************* +* Make a new type available to the factory * +*************************************************/ +void AllocatorFactory::add(const std::string& type, Allocator* allocator) + { + Mutex_Holder lock(factory_lock); + allocator->init(); + alloc[type] = allocator; + } + +/************************************************* +* Set the default allocator type * +*************************************************/ +std::string AllocatorFactory::set_default_allocator(const std::string& alloc) + { + Mutex_Holder lock(factory_lock); + + std::string old_default = default_allocator; + default_allocator = alloc; + return old_default; + } + +/************************************************* +* Destroy an allocator factory * +*************************************************/ +AllocatorFactory::~AllocatorFactory() + { + std::map::iterator iter; + for(iter = alloc.begin(); iter != alloc.end(); iter++) + { + iter->second->destroy(); + delete iter->second; + } + delete factory_lock; + } + +/************************************************* +* Global State * +*************************************************/ +AllocatorFactory* factory = 0; + +} + +/************************************************* +* Get an allocator * +*************************************************/ +Allocator* get_allocator(const std::string& type) + { + if(!factory) + throw Invalid_State("LibraryInitializer not created, or it failed"); + + Allocator* alloc = 0; + + if(type != "") + { + alloc = factory->get(type); + if(alloc) return alloc; + } + + alloc = factory->get("default"); + if(alloc) return alloc; + + alloc = factory->get("locking"); + if(alloc) return alloc; + + throw Exception("Couldn't find an allocator to use in get_allocator"); + } + +/************************************************* +* Set the default allocator type * +*************************************************/ +std::string set_default_allocator(const std::string& type) + { + return factory->set_default_allocator(type); + } + +/************************************************* +* Add new allocator type * +*************************************************/ +bool add_allocator_type(const std::string& type, Allocator* alloc) + { + if(type == "" || factory->get(type)) + return false; + factory->add(type, alloc); + return true; + } + +namespace Init { + +/************************************************* +* Initialize the memory subsystem * +*************************************************/ +void startup_memory_subsystem() + { + factory = new AllocatorFactory; + + add_allocator_type("malloc", new Malloc_Allocator); + add_allocator_type("locking", new Locking_Allocator); + } + +/************************************************* +* Shut down the memory subsystem * +*************************************************/ +void shutdown_memory_subsystem() + { + delete factory; + factory = 0; + } + +} + +} --- botan/allocate.h +++ botan/allocate.h @@ -0,0 +1,46 @@ +/************************************************* +* Allocator Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ALLOCATOR_H__ +#define BOTAN_ALLOCATOR_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Allocator * +*************************************************/ +class Allocator + { + public: + virtual void* allocate(u32bit) const = 0; + virtual void deallocate(void*, u32bit) const = 0; + + virtual void init() {} + virtual void destroy() {} + + virtual ~Allocator() {} + }; + +/************************************************* +* Get an allocator * +*************************************************/ +Allocator* get_allocator(const std::string& = ""); + +/************************************************* +* Set the default allocator type * +*************************************************/ +std::string set_default_allocator(const std::string&); + +/************************************************* +* Add new allocator type * +*************************************************/ +bool add_allocator_type(const std::string&, Allocator*); + +} + +#endif --- botan/arc4.cpp +++ botan/arc4.cpp @@ -0,0 +1,101 @@ +/************************************************* +* ARC4 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Combine Cipher Stream with Message * +*************************************************/ +void ARC4::cipher(const byte in[], byte out[], u32bit length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, buffer.begin() + position, buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + generate(); + } + xor_buf(out, in, buffer.begin() + position, length); + position += length; + } + +/************************************************* +* Generate ARC4 Cipher Stream * +*************************************************/ +void ARC4::generate() + { + u32bit SX, SY; + for(u32bit j = 0; j != buffer.size(); j += 4) + { + SX = state[X+1]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+1] = SY; state[Y] = SX; + buffer[j] = state[(SX + SY) % 256]; + + SX = state[X+2]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+2] = SY; state[Y] = SX; + buffer[j+1] = state[(SX + SY) % 256]; + + SX = state[X+3]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+3] = SY; state[Y] = SX; + buffer[j+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[j+3] = state[(SX + SY) % 256]; + } + position = 0; + } + +/************************************************* +* ARC4 Key Schedule * +*************************************************/ +void ARC4::key(const byte key[], u32bit length) + { + clear(); + for(u32bit j = 0; j != 256; j++) + state[j] = j; + for(u32bit j = 0, state_index = 0; j != 256; j++) + { + state_index = (state_index + key[j % length] + state[j]) % 256; + std::swap(state[j], state[state_index]); + } + for(u32bit j = 0; j <= SKIP; j += buffer.size()) + generate(); + position += (SKIP % buffer.size()); + } + +/************************************************* +* Return the name of this type * +*************************************************/ +std::string ARC4::name() const + { + if(SKIP == 0) return "ARC4"; + if(SKIP == 256) return "MARK-4"; + else return "RC4_skip(" + to_string(SKIP) + ")"; + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void ARC4::clear() throw() + { + state.clear(); + buffer.clear(); + position = X = Y = 0; + } + +/************************************************* +* ARC4 Constructor * +*************************************************/ +ARC4::ARC4(u32bit s) : StreamCipher(1, 32), SKIP(s) + { + clear(); + } + +} --- botan/arc4.h +++ botan/arc4.h @@ -0,0 +1,36 @@ +/************************************************* +* ARC4 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ARC4_H__ +#define BOTAN_ARC4_H__ + +#include + +namespace Botan { + +/************************************************* +* ARC4 * +*************************************************/ +class ARC4 : public StreamCipher + { + public: + void clear() throw(); + std::string name() const; + StreamCipher* clone() const { return new ARC4(SKIP); } + ARC4(u32bit = 0); + ~ARC4() { clear(); } + private: + void cipher(const byte[], byte[], u32bit); + void key(const byte[], u32bit); + void generate(); + const u32bit SKIP; + SecureBuffer buffer; + SecureBuffer state; + u32bit X, Y, position; + }; + +} + +#endif --- botan/asn1.h +++ botan/asn1.h @@ -0,0 +1,38 @@ +/************************************************* +* ASN.1 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ASN1_H__ +#define BOTAN_ASN1_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* BER Decoding Error * +*************************************************/ +struct BER_Decoding_Error : public Decoding_Error + { + BER_Decoding_Error(const std::string& str) : + Decoding_Error("BER: " + str) {} + }; + +/************************************************* +* BER Bad Tag Error * +*************************************************/ +struct BER_Bad_Tag : public BER_Decoding_Error + { + BER_Bad_Tag(const std::string& str, ASN1_Tag tag) : + BER_Decoding_Error(str + ": " + to_string(tag)) {} + BER_Bad_Tag(const std::string& str, ASN1_Tag tag1, ASN1_Tag tag2) : + BER_Decoding_Error(str + ": " + to_string(tag1) + "/" + + to_string(tag2)) {} + }; + +} + +#endif --- botan/asn1_alg.cpp +++ botan/asn1_alg.cpp @@ -0,0 +1,83 @@ +/************************************************* +* Algorithm Identifier Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Create an AlgorithmIdentifier * +*************************************************/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& o, + const MemoryRegion& p) : + oid(o), parameters(p) + { + } + +/************************************************* +* Create an AlgorithmIdentifier * +*************************************************/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + bool use_null) + { + const byte DER_NULL[] = { 0x05, 0x00 }; + + oid = OIDS::lookup(alg_id); + if(use_null) + parameters.append(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); + } + +namespace DER { + +/************************************************* +* DER encode an AlgorithmIdentifier * +*************************************************/ +void encode(DER_Encoder& encoder, const AlgorithmIdentifier& alg_id) + { + encoder.start_sequence(); + DER::encode(encoder, alg_id.oid); + encoder.add_raw_octets(alg_id.parameters); + encoder.end_sequence(); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded AlgorithmIdentifier * +*************************************************/ +void decode(BER_Decoder& source, AlgorithmIdentifier& alg_id) + { + BER_Decoder sequence = BER::get_subsequence(source); + BER::decode(sequence, alg_id.oid); + alg_id.parameters = sequence.get_remaining(); + sequence.verify_end(); + } + +} + +} --- botan/asn1_alt.cpp +++ botan/asn1_alt.cpp @@ -0,0 +1,114 @@ +/************************************************* +* AlternativeName Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Create an AlternativeName * +*************************************************/ +AlternativeName::AlternativeName(const std::string& email_addr, + const std::string& uri, + const std::string& dns) + { + add_attribute("RFC822", email_addr); + add_attribute("DNS", dns); + add_attribute("URI", uri); + } + +/************************************************* +* Add an attribute to an alternative name * +*************************************************/ +void AlternativeName::add_attribute(const std::string& type, + const std::string& str) + { + if(type == "" || str == "") + return; + + typedef std::multimap::iterator iter; + std::pair range = alt_info.equal_range(type); + for(iter j = range.first; j != range.second; j++) + if(j->second == str) + return; + + multimap_insert(alt_info, type, str); + } + +/************************************************* +* Get the attributes of this alternative name * +*************************************************/ +std::multimap AlternativeName::get_attributes() const + { + return alt_info; + } + +/************************************************* +* Return if this object has anything useful * +*************************************************/ +bool AlternativeName::has_items() const + { + return (alt_info.size() > 0); + } + +namespace DER { + +/************************************************* +* DER encode a AlternativeName entry * +*************************************************/ +void encode_entries(DER_Encoder& encoder, const AlternativeName& alt_name, + const std::string& type, ASN1_Tag tagging) + { + std::multimap attr = alt_name.get_attributes(); + typedef std::multimap::iterator iter; + + std::pair range = attr.equal_range(type); + for(iter j = range.first; j != range.second; j++) + { + ASN1_String asn1_string(j->second, IA5_STRING); + DER::encode(encoder, asn1_string, tagging, CONTEXT_SPECIFIC); + } + } + +/************************************************* +* DER encode a AlternativeName * +*************************************************/ +void encode(DER_Encoder& encoder, const AlternativeName& alt_name) + { + encoder.start_sequence(); + encode_entries(encoder, alt_name, "RFC822", ASN1_Tag(1)); + encode_entries(encoder, alt_name, "DNS", ASN1_Tag(2)); + encode_entries(encoder, alt_name, "URI", ASN1_Tag(6)); + encoder.end_sequence(); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded AlternativeName * +*************************************************/ +void decode(BER_Decoder& source, AlternativeName& alt_name) + { + BER_Decoder names = BER::get_subsequence(source); + while(names.more_items()) + { + BER_Object obj = names.get_next_object(); + if(obj.class_tag != CONTEXT_SPECIFIC) + continue; + + ASN1_Tag tag = obj.type_tag; + const std::string value = iso2local(BER::to_string(obj)); + + if(tag == 1) alt_name.add_attribute("RFC822", value); + else if(tag == 2) alt_name.add_attribute("DNS", value); + else if(tag == 6) alt_name.add_attribute("URI", value); + } + } + +} + +} --- botan/asn1_att.cpp +++ botan/asn1_att.cpp @@ -0,0 +1,66 @@ +/************************************************* +* Attribute Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Create an Attribute * +*************************************************/ +Attribute::Attribute(const OID& attr_oid, const MemoryRegion& attr_value) + { + oid = attr_oid; + parameters = attr_value; + } + +/************************************************* +* Create an Attribute * +*************************************************/ +Attribute::Attribute(const std::string& attr_oid, + const MemoryRegion& attr_value) + { + oid = OIDS::lookup(attr_oid); + parameters = attr_value; + } + +namespace DER { + +/************************************************* +* DER encode a Attribute * +*************************************************/ +void encode(DER_Encoder& encoder, const Attribute& attr) + { + encoder.start_sequence(); + DER::encode(encoder, attr.oid); + encoder.start_set(); + encoder.add_raw_octets(attr.parameters); + encoder.end_set(); + encoder.end_sequence(); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded Attribute * +*************************************************/ +void decode(BER_Decoder& source, Attribute& attr) + { + BER_Decoder decoder = BER::get_subsequence(source); + BER::decode(decoder, attr.oid); + + BER_Decoder attributes = BER::get_subset(decoder); + attr.parameters = attributes.get_remaining(); + attributes.verify_end(); + + decoder.verify_end(); + } + +} + +} --- botan/asn1_dn.cpp +++ botan/asn1_dn.cpp @@ -0,0 +1,288 @@ +/************************************************* +* X509_DN Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#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) + { + std::multimap::const_iterator j; + for(j = args.begin(); j != args.end(); j++) + add_attribute(j->first, j->second); + } + +/************************************************* +* Create an X509_DN * +*************************************************/ +X509_DN::X509_DN(const std::multimap& args) + { + std::multimap::const_iterator j; + for(j = args.begin(); j != args.end(); j++) + add_attribute(OIDS::lookup(j->first), j->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; + + typedef std::multimap::iterator rdn_iter; + + std::pair range = dn_info.equal_range(oid); + for(rdn_iter j = range.first; j != range.second; j++) + if(j->second.value() == str) + return; + + multimap_insert(dn_info, oid, ASN1_String(str)); + dn_bits.destroy(); + } + +/************************************************* +* Get the attributes of this X509_DN * +*************************************************/ +std::multimap X509_DN::get_attributes() const + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap retval; + for(rdn_iter j = dn_info.begin(); j != dn_info.end(); j++) + multimap_insert(retval, j->first, j->second.value()); + return retval; + } + +/************************************************* +* Get a single attribute type * +*************************************************/ +std::vector X509_DN::get_attribute(const std::string& attr) const + { + typedef std::multimap::const_iterator rdn_iter; + + const OID oid = OIDS::lookup(deref_info_field(attr)); + std::pair range = dn_info.equal_range(oid); + + std::vector values; + for(rdn_iter j = range.first; j != range.second; j++) + values.push_back(j->second.value()); + return values; + } + +/************************************************* +* Handle the decoding operation of a DN * +*************************************************/ +void X509_DN::do_decode(const MemoryRegion& bits) + { + BER_Decoder sequence(bits); + + while(sequence.more_items()) + { + BER_Decoder rdn = BER::get_subset(sequence); + while(rdn.more_items()) + { + OID oid; + ASN1_String str; + + BER_Decoder ava = BER::get_subsequence(rdn); + BER::decode(ava, oid); + BER::decode(ava, str); + ava.verify_end(); + + add_attribute(oid, str.value()); + } + } + + dn_bits = bits; + } + +/************************************************* +* Return the BER encoded data, if any * +*************************************************/ +SecureVector 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") 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) + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap attr1 = dn1.get_attributes(); + std::multimap attr2 = dn2.get_attributes(); + + if(attr1.size() != attr2.size()) return false; + + rdn_iter p1 = attr1.begin(); + rdn_iter 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); + } + +/************************************************* +* Compare two X509_DNs * +*************************************************/ +bool operator<(const X509_DN& dn1, const X509_DN& dn2) + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap attr1 = dn1.get_attributes(); + std::multimap attr2 = dn2.get_attributes(); + + if(attr1.size() < attr2.size()) return true; + if(attr1.size() > attr2.size()) return false; + + for(rdn_iter p1 = attr1.begin(); p1 != attr1.end(); p1++) + { + std::multimap::const_iterator p2; + 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 { + +namespace { + +/************************************************* +* DER encode a RelativeDistinguishedName * +*************************************************/ +void do_ava(DER_Encoder& encoder, std::multimap& dn_info, + ASN1_Tag string_type, const std::string& oid_str, + bool must_exist = false) + { + typedef std::multimap::iterator rdn_iter; + + 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; + + std::pair range = dn_info.equal_range(oid); + + for(rdn_iter j = range.first; j != range.second; j++) + { + ASN1_String asn1_string(j->second, string_type); + + encoder.start_set(); + encoder.start_sequence(); + DER::encode(encoder, oid); + DER::encode(encoder, asn1_string); + encoder.end_sequence(); + encoder.end_set(); + } + } + +} + +/************************************************* +* DER encode a DistinguishedName * +*************************************************/ +void encode(DER_Encoder& encoder, const X509_DN& dn) + { + std::multimap dn_info = dn.get_attributes(); + SecureVector bits = dn.get_bits(); + + encoder.start_sequence(); + + if(bits.has_items()) + encoder.add_raw_octets(bits); + else + { + do_ava(encoder, dn_info, PRINTABLE_STRING, "X520.Country", true); + do_ava(encoder, dn_info, DIRECTORY_STRING, "X520.State"); + do_ava(encoder, dn_info, DIRECTORY_STRING, "X520.Locality"); + do_ava(encoder, dn_info, DIRECTORY_STRING, "X520.Organization"); + do_ava(encoder, dn_info, DIRECTORY_STRING, "X520.OrganizationalUnit"); + do_ava(encoder, dn_info, DIRECTORY_STRING, "X520.CommonName", true); + do_ava(encoder, dn_info, PRINTABLE_STRING, "X520.SerialNumber"); + } + encoder.end_sequence(); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded DistinguishedName * +*************************************************/ +void decode(BER_Decoder& source, X509_DN& dn) + { + dn = X509_DN(); + BER_Decoder sequence = BER::get_subsequence(source); + SecureVector bits = sequence.get_remaining(); + dn.do_decode(bits); + } + +} + +} --- botan/asn1_ext.cpp +++ botan/asn1_ext.cpp @@ -0,0 +1,65 @@ +/************************************************* +* Extension Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Create an Extension * +*************************************************/ +Extension::Extension(const OID& extn_oid, const MemoryRegion& extn_value) + { + oid = extn_oid; + value = extn_value; + critical = false; + } + +/************************************************* +* Create an Extension * +*************************************************/ +Extension::Extension(const std::string& extn_oid, + const MemoryRegion& extn_value) + { + oid = OIDS::lookup(extn_oid); + value = extn_value; + critical = false; + } + +namespace DER { + +/************************************************* +* DER encode a Extension * +*************************************************/ +void encode(DER_Encoder& encoder, const Extension& extn) + { + encoder.start_sequence(); + DER::encode(encoder, extn.oid); + if(extn.critical) + DER::encode(encoder, true); + DER::encode(encoder, extn.value, OCTET_STRING); + encoder.end_sequence(); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded Extension * +*************************************************/ +void decode(BER_Decoder& source, Extension& extn) + { + BER_Decoder extension = BER::get_subsequence(source); + BER::decode(extension, extn.oid); + BER::decode_optional(extension, extn.critical, BOOLEAN, UNIVERSAL, false); + BER::decode(extension, extn.value, OCTET_STRING); + extension.verify_end(); + } + +} + +} --- botan/asn1_ku.cpp +++ botan/asn1_ku.cpp @@ -0,0 +1,64 @@ +/************************************************* +* KeyUsage Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +namespace DER { + +/************************************************* +* DER encode a KeyUsage BIT STRING * +*************************************************/ +void encode(DER_Encoder& encoder, Key_Constraints usage) + { + if(usage == NO_CONSTRAINTS) + throw Encoding_Error("Cannot encode zero usage constraints"); + + const u32bit unused_bits = low_bit(usage) - 1; + + SecureVector der; + der.append(BIT_STRING); + der.append(2 + ((unused_bits < 8) ? 1 : 0)); + der.append(unused_bits % 8); + der.append((usage >> 8) & 0xFF); + if(usage & 0xFF) + der.append(usage & 0xFF); + + encoder.add_raw_octets(der); + } + +} + +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(u32bit j = 1; j != obj.value.size(); j++) + usage = (obj.value[j] << 8) | usage; + + key_usage = Key_Constraints(usage); + } + +} + +} --- botan/asn1_obj.h +++ botan/asn1_obj.h @@ -0,0 +1,207 @@ +/************************************************* +* Common ASN.1 Objects Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ASN1_OBJ_H__ +#define BOTAN_ASN1_OBJ_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Algorithm Identifier * +*************************************************/ +class AlgorithmIdentifier + { + public: + OID oid; + SecureVector parameters; + + AlgorithmIdentifier() {} + AlgorithmIdentifier(const OID&, const MemoryRegion&); + AlgorithmIdentifier(const std::string&, bool = true); + }; + +/************************************************* +* Extension * +*************************************************/ +class Extension + { + public: + bool critical; + OID oid; + SecureVector value; + + Extension() { critical = false; } + Extension(const OID&, const MemoryRegion&); + Extension(const std::string&, const MemoryRegion&); + }; + +/************************************************* +* Attribute * +*************************************************/ +class Attribute + { + public: + OID oid; + SecureVector parameters; + + Attribute() {} + Attribute(const OID&, const MemoryRegion&); + Attribute(const std::string&, const MemoryRegion&); + }; + +/************************************************* +* X.509 Time * +*************************************************/ +class X509_Time + { + public: + std::string as_string() const; + std::string readable_string() const; + bool time_is_set() const; + + ASN1_Tag tagging() const; + + s32bit cmp(const X509_Time&) const; + s32bit cmp(u64bit) const; + + X509_Time(u64bit); + 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; + }; + +/************************************************* +* Simple String * +*************************************************/ +class ASN1_String + { + public: + 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; + }; + +/************************************************* +* Distinguished Name * +*************************************************/ +class X509_DN + { + public: + std::multimap get_attributes() const; + std::vector get_attribute(const std::string&) 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&); + + void do_decode(const MemoryRegion&); + SecureVector get_bits() const; + + X509_DN(); + X509_DN(const std::multimap&); + X509_DN(const std::multimap&); + private: + std::multimap dn_info; + SecureVector dn_bits; + }; + +/************************************************* +* Alternative Name * +*************************************************/ +class AlternativeName + { + public: + void add_attribute(const std::string&, const std::string&); + std::multimap get_attributes() const; + + bool has_items() const; + + AlternativeName(const std::string& = "", const std::string& = "", + const std::string& = ""); + private: + std::multimap alt_info; + }; + +/************************************************* +* Comparison Operations * +*************************************************/ +bool operator==(const AlgorithmIdentifier&, const AlgorithmIdentifier&); +bool operator!=(const AlgorithmIdentifier&, const AlgorithmIdentifier&); + +bool operator==(const X509_Time&, const X509_Time&); +bool operator!=(const X509_Time&, const X509_Time&); +bool operator<=(const X509_Time&, const X509_Time&); +bool operator>=(const X509_Time&, const X509_Time&); + +bool operator==(const X509_DN&, const X509_DN&); +bool operator!=(const X509_DN&, const X509_DN&); +bool operator<(const X509_DN&, const X509_DN&); + +s32bit validity_check(const X509_Time&, const X509_Time&, u64bit); + +/************************************************* +* DER Encoding Functions * +*************************************************/ +namespace DER { + +void encode(DER_Encoder&, const AlgorithmIdentifier&); +void encode(DER_Encoder&, const Extension&); +void encode(DER_Encoder&, const Attribute&); +void encode(DER_Encoder&, const X509_Time&); +void encode(DER_Encoder&, const X509_Time&, ASN1_Tag); +void encode(DER_Encoder&, const ASN1_String&); +void encode(DER_Encoder&, const ASN1_String&, + ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void encode(DER_Encoder&, const X509_DN&); +void encode(DER_Encoder&, const AlternativeName&); +void encode(DER_Encoder&, Key_Constraints); + +} + +/************************************************* +* BER Decoding Functions * +*************************************************/ +namespace BER { + +void decode(BER_Decoder&, AlgorithmIdentifier&); +void decode(BER_Decoder&, Extension&); +void decode(BER_Decoder&, Attribute&); +void decode(BER_Decoder&, X509_Time&); +void decode(BER_Decoder&, ASN1_String&); +void decode(BER_Decoder&, ASN1_String&, ASN1_Tag, ASN1_Tag); +void decode(BER_Decoder&, X509_DN&); +void decode(BER_Decoder&, AlternativeName&); +void decode(BER_Decoder&, Key_Constraints&); + +} + +/************************************************* +* Insert a key/value pair into a multimap * +*************************************************/ +template +void multimap_insert(std::multimap& multimap, + const K& key, const V& value) + { + multimap.insert(std::make_pair(key, value)); + } + +} + +#endif --- botan/asn1_oid.cpp +++ botan/asn1_oid.cpp @@ -0,0 +1,180 @@ +/************************************************* +* ASN.1 OID Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* ASN.1 OID Constructor * +*************************************************/ +OID::OID(const std::string& oid_str) + { + if(oid_str != "") + { + id = parse_asn1_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(u32bit j = 0; j != id.size(); j++) + { + oid_str += to_string(id[j]); + if(j != 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(u32bit j = 0; j != id.size(); j++) + if(id[j] != oid.id[j]) + 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) + { + std::vector oid1 = a.get_id(); + std::vector oid2 = b.get_id(); + + if(oid1.size() < oid2.size()) + return true; + if(oid1.size() > oid2.size()) + return false; + for(u32bit j = 0; j != oid1.size(); j++) + { + if(oid1[j] < oid2[j]) + return true; + if(oid1[j] > oid2[j]) + return false; + } + return false; + } + +namespace DER { + +/************************************************* +* DER encode an OBJECT IDENTIFIER * +*************************************************/ +void encode(DER_Encoder& encoder, const OID& oid_obj) + { + std::vector oid = oid_obj.get_id(); + + if(oid.size() < 2) + throw Invalid_Argument("DER::encode(OID): OID is invalid"); + + MemoryVector encoding; + encoding.append(40 * oid[0] + oid[1]); + + for(u32bit j = 2; j != oid.size(); j++) + { + if(oid[j] == 0) + encoding.append(0); + else + { + u32bit blocks = high_bit(oid[j]) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + for(u32bit k = 0; k != blocks - 1; k++) + encoding.append(0x80 | ((oid[j] >> 7*(blocks-k-1)) & 0x7F)); + encoding.append(oid[j] & 0x7F); + } + } + encoder.add_object(OBJECT_ID, UNIVERSAL, encoding); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded OBJECT IDENTIFIER * +*************************************************/ +void decode(BER_Decoder& decoder, OID& oid) + { + 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"); + + oid.clear(); + oid += (obj.value[0] / 40); + oid += (obj.value[0] % 40); + + u32bit j = 0; + while(j != obj.value.size() - 1) + { + u32bit component = 0; + while(j != obj.value.size() - 1) + { + j++; + component = (component << 7) + (obj.value[j] & 0x7F); + if(!(obj.value[j] & 0x80)) + break; + } + oid += component; + } + } + +} + +} --- botan/asn1_oid.h +++ botan/asn1_oid.h @@ -0,0 +1,45 @@ +/************************************************* +* ASN.1 OID Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ASN1_OID_H__ +#define BOTAN_ASN1_OID_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* ASN.1 Object Identifier * +*************************************************/ +class OID + { + public: + std::vector get_id() const { return id; } + std::string as_string() const; + bool operator==(const OID&) const; + void clear(); + + OID& operator+=(u32bit); + OID(const std::string& = ""); + private: + std::vector id; + }; + +/************************************************* +* Append another component onto the OID * +*************************************************/ +OID operator+(const OID&, u32bit); + +/************************************************* +* Compare two OIDs * +*************************************************/ +bool operator!=(const OID&, const OID&); +bool operator<(const OID&, const OID&); + +} + +#endif --- botan/asn1_str.cpp +++ botan/asn1_str.cpp @@ -0,0 +1,191 @@ +/************************************************* +* Simple ASN.1 String Types Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Choose an encoding for the string * +*************************************************/ +ASN1_Tag choose_encoding(const std::string& str) + { + 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(u32bit j = 0; j != str.size(); j++) + if(!IS_PRINTABLE[(byte)str[j]]) + { + const std::string type = Config::get_string("x509/ca/str_type"); + if(type == "utf8") return UTF8_STRING; + if(type == "latin1") return T61_STRING; + throw Invalid_Argument("Bad setting for x509/ca/str_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 = local2iso(str); + if(tag == DIRECTORY_STRING) + tag = choose_encoding(iso_8859_str); + + 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 " + + to_string(tag)); + } + +/************************************************* +* Create an ASN1_String * +*************************************************/ +ASN1_String::ASN1_String(const std::string& str) + { + iso_8859_str = local2iso(str); + tag = choose_encoding(iso_8859_str); + } + +/************************************************* +* 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 iso2local(iso_8859_str); + } + +/************************************************* +* Return the type of this string object * +*************************************************/ +ASN1_Tag ASN1_String::tagging() const + { + return tag; + } + +namespace DER { + +/************************************************* +* DER encode an ASN1_String * +*************************************************/ +void encode(DER_Encoder& encoder, const ASN1_String& string, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(string.tagging() == UTF8_STRING) + encoder.add_object(type_tag, class_tag, iso2utf(string.iso_8859())); + else + encoder.add_object(type_tag, class_tag, string.iso_8859()); + } + +/************************************************* +* DER encode an ASN1_String * +*************************************************/ +void encode(DER_Encoder& encoder, const ASN1_String& string) + { + DER::encode(encoder, string, string.tagging(), UNIVERSAL); + } + +} + +namespace BER { + +namespace { + +/************************************************* +* Do any UTF-8/Unicode decoding needed * +*************************************************/ +std::string convert_string(BER_Object obj, ASN1_Tag type) + { + if(type == BMP_STRING) + { + if(obj.value.size() % 2 == 1) + throw BER_Decoding_Error("BMP STRING has an odd number of bytes"); + + std::string value; + for(u32bit j = 0; j != obj.value.size(); j += 2) + { + const byte c1 = obj.value[j]; + const byte c2 = obj.value[j+1]; + + if(c1 != 0) + throw BER_Decoding_Error("BMP STRING has non-Latin1 characters"); + + value += (char)c2; + } + return iso2local(value); + } + else if(type == UTF8_STRING) + return iso2local(utf2iso(BER::to_string(obj))); + else + return iso2local(BER::to_string(obj)); + } + +} + +/************************************************* +* Decode a BER encoded ASN1_String * +*************************************************/ +void decode(BER_Decoder& source, ASN1_String& string, + ASN1_Tag expected_tag, ASN1_Tag real_tag) + { + BER_Object obj = source.get_next_object(); + if(obj.type_tag != expected_tag) + throw BER_Bad_Tag("Unexpected string tag", obj.type_tag); + + string = ASN1_String(convert_string(obj, real_tag), real_tag); + } + +/************************************************* +* Decode a BER encoded ASN1_String * +*************************************************/ +void decode(BER_Decoder& source, ASN1_String& string) + { + BER_Object obj = source.get_next_object(); + string = ASN1_String(convert_string(obj, obj.type_tag), obj.type_tag); + } + +} + +} --- botan/asn1_tm.cpp +++ botan/asn1_tm.cpp @@ -0,0 +1,324 @@ +/************************************************* +* X.509 Time Types Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Convert a time_t to a struct tm * +*************************************************/ +std::tm get_tm(u64bit timer) + { + std::time_t time_val = (std::time_t)timer; + + if((u64bit)time_val != timer) + throw Encoding_Error("X509_Time: time_t overflow with time value " + + to_string(timer)); + + std::tm* tm_p = std::gmtime(&time_val); + if(tm_p == 0) + throw Encoding_Error("X509_Time: gmtime could not encode " + + to_string(timer)); + return (*tm_p); + } + +} + +/************************************************* +* Create an X509_Time * +*************************************************/ +X509_Time::X509_Time(const std::string& time_str) + { + if(time_str == "") + { + year = month = day = hour = minute = second = 0; + return; + } + + std::vector params; + std::string current; + + for(u32bit j = 0; j != time_str.size(); j++) + { + if(is_digit(time_str[j])) + current += time_str[j]; + else + { + if(current != "") + params.push_back(current); + current = ""; + } + } + 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; + + if(year >= 2050) + tag = GENERALIZED_TIME; + else + tag = UTC_TIME; + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + time_str); + } + +/************************************************* +* Create an X509_Time * +*************************************************/ +X509_Time::X509_Time(u64bit timer) + { + std::tm time_info = get_tm(timer); + + year = time_info.tm_year + 1900; + month = time_info.tm_mon + 1; + day = time_info.tm_mday; + hour = time_info.tm_hour; + minute = time_info.tm_min; + second = time_info.tm_sec; + + if(year >= 2050) + tag = GENERALIZED_TIME; + else + tag = UTC_TIME; + } + +/************************************************* +* Create an X509_Time * +*************************************************/ +X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t) + { + if(tag != GENERALIZED_TIME && tag != UTC_TIME) + throw Invalid_Argument("X509_Time: Invalid tag " + to_string(tag)); + if(tag == GENERALIZED_TIME && t_spec.size() != 13 && t_spec.size() != 15) + throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec); + if(tag == UTC_TIME && t_spec.size() != 11 && t_spec.size() != 13) + throw Invalid_Argument("Invalid UTCTime: " + t_spec); + if(t_spec[t_spec.size()-1] != 'Z') + throw Invalid_Argument("Invalid time encoding: " + t_spec); + + const u32bit YEAR_SIZE = (tag == UTC_TIME) ? 2 : 4; + + std::vector params; + std::string current; + + for(u32bit j = 0; j != YEAR_SIZE; j++) + current += t_spec[j]; + params.push_back(current); + current = ""; + + for(u32bit j = YEAR_SIZE; j != t_spec.size() - 1; j++) + { + current += t_spec[j]; + if(current.size() == 2) + { + params.push_back(current); + current = ""; + } + } + + 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; + + if(tag == UTC_TIME) + { + if(year >= 50) year += 1900; + else year += 2000; + } + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + t_spec); + } + +/************************************************* +* 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"); + + std::string asn1rep; + if(tag == GENERALIZED_TIME) + asn1rep = to_string(year, 4); + else + { + if(year < 1950 || year >= 2050) + throw Encoding_Error("X509_Time: The time " + readable_string() + + " cannot be encoded as a UTCTime"); + u32bit asn1year = (year >= 2000) ? (year - 2000) : (year - 1900); + asn1rep = to_string(asn1year, 2); + } + asn1rep += to_string(month, 2) + to_string(day, 2); + asn1rep += to_string(hour, 2) + to_string(minute, 2) + to_string(second, 2); + asn1rep += "Z"; + return asn1rep; + } + +/************************************************* +* 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 readable; + readable += to_string(year, 4) + "/"; + readable += to_string(month ) + "/"; + readable += to_string(day ) + " "; + readable += to_string(hour ) + ":"; + readable += to_string(minute, 2) + ":"; + readable += to_string(second, 2) + " UTC"; + return readable; + } + +/************************************************* +* 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; + } + +/************************************************* +* Return the type of this Time object * +*************************************************/ +ASN1_Tag X509_Time::tagging() const + { + return tag; + } + +/************************************************* +* 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 this time against another * +*************************************************/ +s32bit X509_Time::cmp(u64bit seconds) const + { + return cmp(X509_Time(seconds)); + } + +/************************************************* +* 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); } + +/************************************************* +* Do a validity check * +*************************************************/ +s32bit validity_check(const X509_Time& start, const X509_Time& end, + u64bit current_time) + { + const u32bit ALLOWABLE_SLIP = Config::get_time("x509/validity_slack"); + const s32bit NOT_YET_VALID = -1, VALID_TIME = 0, EXPIRED = 1; + + if(start.cmp(current_time + ALLOWABLE_SLIP) > 0) + return NOT_YET_VALID; + if(end.cmp(current_time - ALLOWABLE_SLIP) < 0) + return EXPIRED; + return VALID_TIME; + } + +namespace DER { + +/************************************************* +* DER encode an X509_Time * +*************************************************/ +void encode(DER_Encoder& encoder, const X509_Time& obj, ASN1_Tag tagging) + { + if(tagging != GENERALIZED_TIME && tagging != UTC_TIME) + throw Invalid_Argument("DER::encode: Bad encoding tag for time value"); + encoder.add_object(tagging, UNIVERSAL, local2iso(obj.as_string())); + } + +/************************************************* +* DER encode an X509_Time * +*************************************************/ +void encode(DER_Encoder& encoder, const X509_Time& obj) + { + DER::encode(encoder, obj, obj.tagging()); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded X509_Time * +*************************************************/ +void decode(BER_Decoder& source, X509_Time& obj) + { + BER_Object ber_obj = source.get_next_object(); + obj = X509_Time(iso2local(BER::to_string(ber_obj)), ber_obj.type_tag); + } + +} + +} --- botan/authors.txt +++ botan/authors.txt @@ -0,0 +1,8 @@ +The main author of Botan is: + +Name: Jack Lloyd +Email: address@hidden +PGP Key Fingerprint: 2DD2 95F9 C7E3 A15E AF29 80E1 D6A9 A5B9 4DCD F398 + +Also see doc/thanks.txt for a list of people who have contributed code, bug +reports, ideas, and/or useful information. --- botan/barrett.cpp +++ botan/barrett.cpp @@ -0,0 +1,66 @@ +/************************************************* +* Barrett Reducer Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Precompute values * +*************************************************/ +BarrettReducer::BarrettReducer(const BigInt& mod) : ModularReducer(mod) + { + k = modulus.sig_words(); + mu.set_bit(MP_WORD_BITS * 2 * k); + mu /= modulus; + max_bits = MP_WORD_BITS * 2 * k; + + if(mu.size() > 8 && !power_of_2(mu.size())) + mu.grow_reg((1 << high_bit(mu.size())) - mu.size()); + } + +/************************************************* +* Barrett Reduction * +*************************************************/ +BigInt BarrettReducer::reduce(const BigInt& x) const + { + if(x.is_positive() && x < modulus) + return x; + if(x.bits() > max_bits) + return (x % modulus); + + t1 = x; + t1.set_sign(BigInt::Positive); + + t1 >>= (MP_WORD_BITS * (k - 1)); + t1 *= mu; + t1 >>= (MP_WORD_BITS * (k + 1)); + + t1 *= modulus; + t1.mask_bits(MP_WORD_BITS * (k+1)); + + t2 = x; + t2.set_sign(BigInt::Positive); + t2.mask_bits(MP_WORD_BITS * (k+1)); + + t2 -= t1; + + if(t2.is_negative()) + { + BigInt b_to_k1(BigInt::Power2, MP_WORD_BITS * (k+1)); + t2 += b_to_k1; + } + while(t2 >= modulus) + t2 -= modulus; + + if(x.is_negative() && t2.is_nonzero()) + t2 = modulus - t2; + + return t2; + } + +} --- botan/barrett.h +++ botan/barrett.h @@ -0,0 +1,30 @@ +/************************************************* +* Barrett Reducer Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BARRETT_H__ +#define BOTAN_BARRETT_H__ + +#include + +namespace Botan { + +/************************************************* +* Barrett Reducer * +*************************************************/ +class BarrettReducer : public ModularReducer + { + public: + BigInt reduce(const BigInt&) const; + + BarrettReducer(const BigInt&); + private: + u32bit max_bits, k; + BigInt mu; + mutable BigInt t1, t2; + }; + +} + +#endif --- botan/base.cpp +++ botan/base.cpp @@ -0,0 +1,258 @@ +/************************************************* +* Base Classes Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* SymmetricAlgorithm Constructor * +*************************************************/ +SymmetricAlgorithm::SymmetricAlgorithm(u32bit key_min, u32bit key_max, + u32bit key_mod) : + MAXIMUM_KEYLENGTH(key_max ? key_max : key_min), + MINIMUM_KEYLENGTH(key_min), + KEYLENGTH_MULTIPLE(key_mod) + { + } + +/************************************************* +* Query if the keylength is valid * +*************************************************/ +bool SymmetricAlgorithm::valid_keylength(u32bit length) const + { + return ((length >= MINIMUM_KEYLENGTH) && + (length <= MAXIMUM_KEYLENGTH) && + (length % KEYLENGTH_MULTIPLE == 0)); + } + +/************************************************* +* Set the key * +*************************************************/ +void SymmetricAlgorithm::set_key(const SymmetricKey& algo_key) + throw(Invalid_Key_Length) + { + set_key(algo_key.begin(), algo_key.length()); + } + +/************************************************* +* Set the key * +*************************************************/ +void SymmetricAlgorithm::set_key(const byte algo_key[], u32bit length) + throw(Invalid_Key_Length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key(algo_key, length); + } + +/************************************************* +* BlockCipher Constructor * +*************************************************/ +BlockCipher::BlockCipher(u32bit block, u32bit key_min, u32bit key_max, + u32bit key_mod) : + SymmetricAlgorithm(key_min, key_max, key_mod), + BLOCK_SIZE(block) + { + } + +/************************************************* +* StreamCipher Constructor * +*************************************************/ +StreamCipher::StreamCipher(u32bit key_min, u32bit key_max, u32bit key_mod, + u32bit iv_len) : + SymmetricAlgorithm(key_min, key_max, key_mod), IV_LENGTH(iv_len) + { + } + +/************************************************* +* BufferedComputation Constructor * +*************************************************/ +BufferedComputation::BufferedComputation(u32bit olen) : OUTPUT_LENGTH(olen) + { + } + +/************************************************* +* HashFunction Constructor * +*************************************************/ +HashFunction::HashFunction(u32bit hlen, u32bit blen) : + BufferedComputation(hlen), HASH_BLOCK_SIZE(blen) + { + } + +/************************************************* +* MessageAuthenticationCode Constructor * +*************************************************/ +MessageAuthenticationCode::MessageAuthenticationCode(u32bit mlen, + u32bit key_min, + u32bit key_max, + u32bit key_mod) : + BufferedComputation(mlen), + SymmetricAlgorithm(key_min, key_max, key_mod) + { + } + +/************************************************* +* Default MAC verification operation * +*************************************************/ +bool MessageAuthenticationCode::verify_mac(const byte mac[], u32bit length) + { + SecureVector our_mac = final(); + if(our_mac.size() != length) + return false; + for(u32bit j = 0; j != length; j++) + if(mac[j] != our_mac[j]) + return false; + return true; + } + +/************************************************* +* Default StreamCipher Resync Operation * +*************************************************/ +void StreamCipher::resync(const byte[], u32bit length) + { + if(length) + throw Exception("The stream cipher " + name() + + " does not support resyncronization"); + } + +/************************************************* +* Default StreamCipher Seek Operation * +*************************************************/ +void StreamCipher::seek(u32bit) + { + throw Exception("The stream cipher " + name() + " does not support seek()"); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +void BufferedComputation::update(const byte in[], u32bit n) + { + add_data(in, n); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +void BufferedComputation::update(const MemoryRegion& in) + { + add_data(in, in.size()); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +void BufferedComputation::update(const std::string& str) + { + update((const byte*)str.c_str(), str.size()); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +void BufferedComputation::update(byte in) + { + update(&in, 1); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +SecureVector BufferedComputation::final() + { + SecureVector output(OUTPUT_LENGTH); + final_result(output); + return output; + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +SecureVector BufferedComputation::process(const byte in[], u32bit len) + { + update(in, len); + return final(); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +SecureVector BufferedComputation::process(const MemoryRegion& in) + { + update(in, in.size()); + return final(); + } + +/************************************************* +* Hashing/MACing * +*************************************************/ +SecureVector BufferedComputation::process(const std::string& in) + { + update(in); + return final(); + } + +/************************************************* +* Default fast poll for EntropySources * +*************************************************/ +u32bit EntropySource::fast_poll(byte buf[], u32bit len) + { + return slow_poll(buf, len); + } + +/************************************************* +* Add entropy to internal state * +*************************************************/ +void RandomNumberGenerator::add_entropy(const byte random[], u32bit length) + { + add_randomness(random, length); + } + +/************************************************* +* Add entropy to internal state * +*************************************************/ +void RandomNumberGenerator::add_entropy(EntropySource& source, bool slowpoll) + { + SecureVector entropy(slowpoll ? 192 : 64); + u32bit returned; + + if(slowpoll) returned = source.slow_poll(entropy, entropy.size()); + else returned = source.fast_poll(entropy, entropy.size()); + + add_entropy(entropy, returned); + } + +/************************************************* +* Update the internal entropy count * +*************************************************/ +void RandomNumberGenerator::update_entropy(const byte data[], u32bit length, + u32bit state_size) throw() + { + if(entropy == 8*state_size) + return; + entropy += entropy_estimate(data, length); + entropy = std::min(entropy, 8*state_size); + } + +/************************************************* +* Return the version as a string * +*************************************************/ +std::string version_string() + { + return "Botan " + to_string(version_major()) + "." + + to_string(version_minor()) + "." + + to_string(version_patch()); + } + +/************************************************* +* 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; } + +} --- botan/base.h +++ botan/base.h @@ -0,0 +1,172 @@ +/************************************************* +* Base Classes Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BASE_H__ +#define BOTAN_BASE_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Constants * +*************************************************/ +static const u32bit DEFAULT_BUFFERSIZE = BOTAN_DEFAULT_BUFFER_SIZE; + +/************************************************* +* Algorithm * +*************************************************/ +class Algorithm + { + public: + virtual void clear() throw() {}; + virtual std::string name() const = 0; + virtual ~Algorithm() {} + private: + Algorithm& operator=(const Algorithm&) { return (*this); } + }; + +/************************************************* +* Symmetric Algorithm * +*************************************************/ +class SymmetricAlgorithm : public Algorithm + { + public: + const u32bit MAXIMUM_KEYLENGTH, MINIMUM_KEYLENGTH, KEYLENGTH_MULTIPLE; + void set_key(const SymmetricKey&) throw(Invalid_Key_Length); + void set_key(const byte[], u32bit) throw(Invalid_Key_Length); + bool valid_keylength(u32bit) const; + SymmetricAlgorithm(u32bit, u32bit, u32bit); + virtual ~SymmetricAlgorithm() {} + private: + virtual void key(const byte[], u32bit) = 0; + }; + +/************************************************* +* Block Cipher * +*************************************************/ +class BlockCipher : public SymmetricAlgorithm + { + public: + const u32bit BLOCK_SIZE; + void encrypt(const byte in[], byte out[]) const { enc(in, out); } + void decrypt(const byte in[], byte out[]) const { dec(in, out); } + void encrypt(byte block[]) const { enc(block, block); } + void decrypt(byte block[]) const { dec(block, block); } + virtual BlockCipher* clone() const = 0; + BlockCipher(u32bit, u32bit, u32bit = 0, u32bit = 1); + virtual ~BlockCipher() {} + private: + virtual void enc(const byte[], byte[]) const = 0; + virtual void dec(const byte[], byte[]) const = 0; + }; + +/************************************************* +* Stream Cipher * +*************************************************/ +class StreamCipher : public SymmetricAlgorithm + { + public: + const u32bit IV_LENGTH; + void encrypt(const byte i[], byte o[], u32bit len) { cipher(i, o, len); } + void decrypt(const byte i[], byte o[], u32bit len) { cipher(i, o, len); } + void encrypt(byte in[], u32bit len) { cipher(in, in, len); } + void decrypt(byte in[], u32bit len) { cipher(in, in, len); } + + virtual void resync(const byte[], u32bit); + virtual void seek(u32bit); + + virtual StreamCipher* clone() const = 0; + StreamCipher(u32bit, u32bit = 0, u32bit = 1, u32bit = 0); + virtual ~StreamCipher() {} + private: + virtual void cipher(const byte[], byte[], u32bit) = 0; + }; + +/************************************************* +* Buffered Computation * +*************************************************/ +class BufferedComputation : public Algorithm + { + public: + const u32bit OUTPUT_LENGTH; + void update(const byte[], u32bit); + void update(const MemoryRegion&); + void update(const std::string&); + void update(byte); + void final(byte out[]) { final_result(out); } + SecureVector final(); + SecureVector process(const byte[], u32bit); + SecureVector process(const MemoryRegion&); + SecureVector process(const std::string&); + BufferedComputation(u32bit); + virtual ~BufferedComputation() {} + private: + virtual void add_data(const byte[], u32bit) = 0; + virtual void final_result(byte[]) = 0; + }; + +/************************************************* +* Hash Function * +*************************************************/ +class HashFunction : public BufferedComputation + { + public: + const u32bit HASH_BLOCK_SIZE; + virtual HashFunction* clone() const = 0; + HashFunction(u32bit, u32bit = 0); + virtual ~HashFunction() {} + }; + +/************************************************* +* Message Authentication Code * +*************************************************/ +class MessageAuthenticationCode : public BufferedComputation, + public SymmetricAlgorithm + { + public: + virtual std::string name() const = 0; + virtual MessageAuthenticationCode* clone() const = 0; + virtual bool verify_mac(const byte[], u32bit); + MessageAuthenticationCode(u32bit, u32bit, u32bit = 0, u32bit = 1); + virtual ~MessageAuthenticationCode() {} + }; + +/************************************************* +* Entropy Source * +*************************************************/ +class EntropySource + { + public: + virtual u32bit slow_poll(byte[], u32bit) = 0; + virtual u32bit fast_poll(byte[], u32bit); + virtual ~EntropySource() {} + }; + +/************************************************* +* Random Number Generator * +*************************************************/ +class RandomNumberGenerator : public Algorithm + { + public: + virtual void randomize(byte[], u32bit) throw(PRNG_Unseeded) = 0; + virtual bool is_seeded() const { return true; } + void add_entropy(const byte[], u32bit); + void add_entropy(EntropySource&, bool = true); + virtual ~RandomNumberGenerator() {} + protected: + void update_entropy(const byte[], u32bit, u32bit) throw(); + u32bit entropy; + private: + virtual void add_randomness(const byte[], u32bit) throw() = 0; + }; + +} + +#endif --- botan/base64.cpp +++ botan/base64.cpp @@ -0,0 +1,217 @@ +/************************************************* +* Base64 Encoder/Decoder Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Base64_Encoder Constructor * +*************************************************/ +Base64_Encoder::Base64_Encoder(bool breaks, u32bit length) : + line_length(breaks ? length : 0) + { + in.create(48); + out.create(4); + + counter = position = 0; + } + +/************************************************* +* Base64 Encoding Operation * +*************************************************/ +void Base64_Encoder::encode(const byte in[3], byte out[4]) + { + 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) )]; + } + +/************************************************* +* Encode and send a block * +*************************************************/ +void Base64_Encoder::encode_and_send(const byte block[], u32bit length) + { + for(u32bit j = 0; j != length; j += 3) + { + encode(block + j, out); + do_output(out, 4); + } + } + +/************************************************* +* Handle the output * +*************************************************/ +void Base64_Encoder::do_output(const byte input[], u32bit length) + { + if(line_length == 0) + send(input, length); + else + { + u32bit remaining = length, offset = 0; + while(remaining) + { + u32bit sent = std::min(line_length - counter, remaining); + send(input + offset, sent); + counter += sent; + remaining -= sent; + offset += sent; + if(counter == line_length) + { + send('\n'); + counter = 0; + } + } + } + } + +/************************************************* +* Convert some data into Base64 * +*************************************************/ +void Base64_Encoder::write(const byte input[], u32bit length) + { + in.copy(position, input, length); + if(position + length >= in.size()) + { + encode_and_send(in, 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(); + } + in.copy(input, length); + position = 0; + } + position += length; + } + +/************************************************* +* Flush buffers * +*************************************************/ +void Base64_Encoder::end_msg() + { + u32bit start_of_last_block = 3 * (position / 3), + left_over = position % 3; + encode_and_send(in, start_of_last_block); + + if(left_over) + { + SecureBuffer remainder(in + start_of_last_block, left_over); + + encode(remainder, out); + + u32bit empty_bits = 8 * (3 - left_over), index = 4 - 1; + while(empty_bits >= 8) + { + out[index--] = '='; + empty_bits -= 6; + } + + do_output(out, 4); + } + + // XXX: monotone requires a terminating newline in all cases, + // for compatibility with cryptopp. + send('\n'); + + counter = position = 0; + } + +/************************************************* +* Base64_Decoder Constructor * +*************************************************/ +Base64_Decoder::Base64_Decoder(Decoder_Checking c) : checking(c) + { + in.create(48); + out.create(3); + position = 0; + } + +/************************************************* +* Check if a character is a valid Base64 char * +*************************************************/ +bool Base64_Decoder::is_valid(byte in) + { + return (BASE64_TO_BIN[in] != 0x80); + } + +/************************************************* +* Base64 Decoding Operation * +*************************************************/ +void Base64_Decoder::decode(const byte in[4], byte out[3]) + { + out[0] = (byte)((BASE64_TO_BIN[in[0]] << 2) | (BASE64_TO_BIN[in[1]] >> 4)); + out[1] = (byte)((BASE64_TO_BIN[in[1]] << 4) | (BASE64_TO_BIN[in[2]] >> 2)); + out[2] = (byte)((BASE64_TO_BIN[in[2]] << 6) | (BASE64_TO_BIN[in[3]])); + } + +/************************************************* +* Decode and send a block * +*************************************************/ +void Base64_Decoder::decode_and_send(const byte block[], u32bit length) + { + for(u32bit j = 0; j != length; j += 4) + { + decode(block + j, out); + send(out, 3); + } + } + +/************************************************* +* Handle processing an invalid character * +*************************************************/ +void Base64_Decoder::handle_bad_char(byte c) + { + if(checking == NONE) return; + if((checking == IGNORE_WS) && is_space(c)) return; + throw Decoding_Error("Base64_Decoder: Invalid base64 character: " + c); + } + +/************************************************* +* Convert some data from Base64 * +*************************************************/ +void Base64_Decoder::write(const byte input[], u32bit length) + { + for(u32bit j = 0; j != length; j++) + { + if(is_valid(input[j])) + in[position++] = input[j]; + else + handle_bad_char(input[j]); + + if(position == in.size()) + { + decode_and_send(in, in.size()); + position = 0; + } + } + } + +/************************************************* +* Flush buffers * +*************************************************/ +void Base64_Decoder::end_msg() + { + if(position != 0) + { + u32bit start_of_last_block = 4 * (position / 4), + left_over = position % 4; + decode_and_send(in, start_of_last_block); + + if(left_over) + { + SecureBuffer remainder(in + start_of_last_block, left_over); + decode(remainder, out); + send(out, ((left_over == 1) ? (1) : (left_over - 1))); + } + } + position = 0; + } + +} --- botan/base64.h +++ botan/base64.h @@ -0,0 +1,58 @@ +/************************************************* +* Base64 Encoder/Decoder Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BASE64_H__ +#define BOTAN_BASE64_H__ + +#include + +namespace Botan { + +/************************************************* +* Base64 Encoder * +*************************************************/ +class Base64_Encoder : public Filter + { + public: + static void encode(const byte[3], byte[4]); + + void write(const byte[], u32bit); + void end_msg(); + Base64_Encoder(bool = true, u32bit = 72); + private: + void encode_and_send(const byte[], u32bit); + void do_output(const byte[], u32bit); + static const byte BIN_TO_BASE64[64]; + + const u32bit line_length; + SecureVector in, out; + u32bit position, counter; + }; + +/************************************************* +* Base64 Decoder * +*************************************************/ +class Base64_Decoder : public Filter + { + public: + static void decode(const byte[4], byte[3]); + static bool is_valid(byte); + + void write(const byte[], u32bit); + void end_msg(); + Base64_Decoder(Decoder_Checking = NONE); + private: + void decode_and_send(const byte[], u32bit); + void handle_bad_char(byte); + static const byte BASE64_TO_BIN[256]; + + const Decoder_Checking checking; + SecureVector in, out; + u32bit position; + }; + +} + +#endif --- botan/base_eng.h +++ botan/base_eng.h @@ -0,0 +1,57 @@ +/************************************************* +* Default Engine Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DEFAULT_ENGINE_H__ +#define BOTAN_DEFAULT_ENGINE_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Default Engine * +*************************************************/ +class Default_Engine : public Engine + { + public: + IF_Operation* if_op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&) const; + DSA_Operation* dsa_op(const DL_Group&, const BigInt&, + const BigInt&) const; + NR_Operation* nr_op(const DL_Group&, const BigInt&, const BigInt&) const; + ELG_Operation* elg_op(const DL_Group&, const BigInt&, + const BigInt&) const; + DH_Operation* dh_op(const DL_Group&, const BigInt&) const; + ModularReducer* reducer(const BigInt&, bool) const; + + const BlockCipher* block_cipher(const std::string&) const; + const StreamCipher* stream_cipher(const std::string&) const; + const HashFunction* hash(const std::string&) const; + const MessageAuthenticationCode* mac(const std::string&) const; + + Default_Engine(); + ~Default_Engine(); + private: + void add_algorithm(BlockCipher*) const; + void add_algorithm(StreamCipher*) const; + void add_algorithm(HashFunction*) const; + void add_algorithm(MessageAuthenticationCode*) const; + + mutable std::map bc_map; + mutable std::map sc_map; + mutable std::map hf_map; + mutable std::map mac_map; + + Mutex* bc_map_lock; + Mutex* sc_map_lock; + Mutex* hf_map_lock; + Mutex* mac_map_lock; + }; + +} + +#endif --- botan/basefilt.cpp +++ botan/basefilt.cpp @@ -0,0 +1,81 @@ +/************************************************* +* Basic Filters Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Chain Constructor * +*************************************************/ +Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + if(f1) { attach(f1); incr_owns(); } + if(f2) { attach(f2); incr_owns(); } + if(f3) { attach(f3); incr_owns(); } + if(f4) { attach(f4); incr_owns(); } + } + +/************************************************* +* Chain Constructor * +*************************************************/ +Chain::Chain(Filter* filters[], u32bit count) + { + for(u32bit j = 0; j != count; j++) + if(filters[j]) + { + attach(filters[j]); + incr_owns(); + } + } + +/************************************************* +* Fork Constructor * +*************************************************/ +Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + u32bit used = 0; + if(f1) used = 1; + if(f2) used = 2; + if(f3) used = 3; + if(f4) used = 4; + set_port_count(used); + if(f1) next[0] = f1; + if(f2) next[1] = f2; + if(f3) next[2] = f3; + if(f4) next[3] = f4; + } + +/************************************************* +* Fork Constructor * +*************************************************/ +Fork::Fork(Filter* filters[], u32bit count) : Filter(count) + { + for(u32bit j = 0; j != count; j++) + next[j] = filters[j]; + } + +/************************************************* +* Set the algorithm key * +*************************************************/ +void Keyed_Filter::set_key(const SymmetricKey& key) + { + if(base_ptr) + base_ptr->set_key(key); + else + throw Invalid_State("Keyed_Filter::set_key: No base algorithm set"); + } + +/************************************************* +* Check if a keylength is valid * +*************************************************/ +bool Keyed_Filter::valid_keylength(u32bit n) const + { + if(base_ptr) + return base_ptr->valid_keylength(n); + throw Invalid_State("Keyed_Filter::valid_keylength: No base algorithm set"); + } + +} --- botan/basefilt.h +++ botan/basefilt.h @@ -0,0 +1,55 @@ +/************************************************* +* Basic Filters Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BASEFILT_H__ +#define BOTAN_BASEFILT_H__ + +#include + +namespace Botan { + +/************************************************* +* Chain * +*************************************************/ +class Chain : public Filter + { + public: + void write(const byte input[], u32bit length) { send(input, length); } + + Chain(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + Chain(Filter*[], u32bit); + }; + +/************************************************* +* Fork * +*************************************************/ +class Fork : public Filter + { + public: + void write(const byte input[], u32bit length) { send(input, length); } + void set_port(u32bit n) { set_port(n); } + + Fork(Filter*, Filter*, Filter* = 0, Filter* = 0); + Fork(Filter*[], u32bit); + }; + +/************************************************* +* Keyed Filter * +*************************************************/ +class Keyed_Filter : public Filter + { + public: + virtual void set_key(const SymmetricKey&); + virtual void set_iv(const InitializationVector&) {} + virtual bool valid_keylength(u32bit) const; + + Keyed_Filter() { base_ptr = 0; } + protected: + SymmetricAlgorithm* base_ptr; + }; + +} + +#endif --- botan/ber_code.cpp +++ botan/ber_code.cpp @@ -0,0 +1,239 @@ +/************************************************* +* BER Decoding Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +namespace { + +/************************************************* +* Check an object's type and size * +*************************************************/ +void check_object(const BER_Object& obj, + ASN1_Tag type_tag, ASN1_Tag class_tag, + u32bit length = 0, bool check_length = false) + { + if(obj.type_tag != type_tag || obj.class_tag != class_tag) + throw BER_Decoding_Error("Tag mismatch when decoding"); + if(check_length && obj.value.size() != length) + throw BER_Decoding_Error("Incorrect size for type"); + } + +} + +namespace BER { + +/************************************************* +* Decode a BER encoded NULL * +*************************************************/ +void decode_null(BER_Decoder& decoder) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, NULL_TAG, UNIVERSAL, 0, true); + } + +/************************************************* +* Decode a BER encoded BOOLEAN * +*************************************************/ +void decode(BER_Decoder& decoder, bool& out) + { + decode(decoder, out, BOOLEAN, UNIVERSAL); + } + +/************************************************* +* Decode a small BER encoded INTEGER * +*************************************************/ +void decode(BER_Decoder& decoder, u32bit& out) + { + decode(decoder, out, INTEGER, UNIVERSAL); + } + +/************************************************* +* Decode a BER encoded INTEGER * +*************************************************/ +void decode(BER_Decoder& decoder, BigInt& out) + { + decode(decoder, out, INTEGER, UNIVERSAL); + } + +/************************************************* +* BER decode a BIT STRING or OCTET STRING * +*************************************************/ +void decode(BER_Decoder& decoder, MemoryRegion& out, ASN1_Tag real_type) + { + decode(decoder, out, real_type, real_type, UNIVERSAL); + } + +/************************************************* +* Decode a BER encoded BOOLEAN * +*************************************************/ +void decode(BER_Decoder& decoder, bool& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, type_tag, class_tag, 1, true); + out = (obj.value[0]) ? true : false; + } + +/************************************************* +* Decode a small BER encoded INTEGER * +*************************************************/ +void decode(BER_Decoder& decoder, u32bit& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BigInt integer; + decode(decoder, integer, type_tag, class_tag); + out = integer.to_u32bit(); + } + +/************************************************* +* Decode a BER encoded INTEGER * +*************************************************/ +void decode(BER_Decoder& decoder, BigInt& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, type_tag, class_tag); + + out = 0; + if(obj.value.is_empty()) + return; + + const bool negative = (obj.value[0] & 0x80) ? true : false; + + if(negative) + { + for(u32bit j = obj.value.size(); j > 0; j--) + if(obj.value[j-1]--) + break; + for(u32bit j = 0; j != obj.value.size(); j++) + obj.value[j] = ~obj.value[j]; + } + + out = BigInt(obj.value, obj.value.size()); + + if(negative) + out.flip_sign(); + } + +/************************************************* +* BER decode a BIT STRING or OCTET STRING * +*************************************************/ +void decode(BER_Decoder& decoder, MemoryRegion& 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 = decoder.get_next_object(); + check_object(obj, 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.set(obj.value + 1, obj.value.size() - 1); + } + } + +/************************************************* +* Decode and return a BER encoded SEQUENCE * +*************************************************/ +BER_Decoder get_subsequence(BER_Decoder& decoder) + { + return get_subsequence(decoder, SEQUENCE, CONSTRUCTED); + } + +/************************************************* +* Decode and return a BER encoded SET * +*************************************************/ +BER_Decoder get_subset(BER_Decoder& decoder) + { + return get_subset(decoder, SET, CONSTRUCTED); + } + +/************************************************* +* Decode and return a BER encoded SEQUENCE * +*************************************************/ +BER_Decoder get_subsequence(BER_Decoder& decoder, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + return BER_Decoder(obj.value, obj.value.size()); + } + +/************************************************* +* Decode and return a BER encoded SET * +*************************************************/ +BER_Decoder get_subset(BER_Decoder& decoder, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + return BER_Decoder(obj.value, obj.value.size()); + } + +/************************************************* +* Convert a BER object into a string object * +*************************************************/ +std::string to_string(const BER_Object& obj) + { + std::string str((const char*)obj.value.begin(), obj.value.size()); + return str; + } + +/************************************************* +* Decode an OPTIONAL string type * +*************************************************/ +bool decode_optional_string(BER_Decoder& in, MemoryRegion& out, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = in.get_next_object(); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + if(class_tag & CONSTRUCTED) + { + BER_Decoder stored_value(obj.value); + BER::decode(stored_value, out, real_type); + stored_value.verify_end(); + } + else + { + in.push_back(obj); + BER::decode(in, out, real_type, type_tag, class_tag); + } + return true; + } + else + { + out.clear(); + in.push_back(obj); + return false; + } + } + +/************************************************* +* Do heuristic tests for BER data * +*************************************************/ +bool maybe_BER(DataSource& source) + { + byte first_byte; + if(!source.peek_byte(first_byte)) + throw Stream_IO_Error("BER::maybe_BER: Source was empty"); + + if(first_byte == (SEQUENCE | CONSTRUCTED)) + return true; + return false; + } + +} + +} --- botan/ber_dec.cpp +++ botan/ber_dec.cpp @@ -0,0 +1,270 @@ +/************************************************* +* BER Decoder Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +namespace { + +/************************************************* +* BER decode an ASN.1 type tag * +*************************************************/ +u32bit 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; + } + + u32bit tag_bytes = 1; + class_tag = ASN1_Tag(b & 0xE0); + + u32bit tag_buf = 0; + while(true) + { + if(!ber->read_byte(b)) + throw Decoding_Error("BER long-form tag truncated"); + if(tag_buf & 0xFF000000) + throw Decoding_Error("BER long-form tag overflow"); + 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 * +*************************************************/ +u32bit find_eoc(DataSource*); + +/************************************************* +* BER decode an ASN.1 length field * +*************************************************/ +u32bit decode_length(DataSource* ber, u32bit& 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"); + + u32bit length = 0; + + for(u32bit j = 0; j != field_size - 1; j++) + { + 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 * +*************************************************/ +u32bit decode_length(DataSource* ber) + { + u32bit dummy; + return decode_length(ber, dummy); + } + +/************************************************* +* Find the EOC marker * +*************************************************/ +u32bit find_eoc(DataSource* ber) + { + SecureVector data; + + while(true) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + + const u32bit got = ber->peek(buffer, buffer.size(), data.size()); + if(got == 0) + break; + data.append(buffer, got); + } + + DataSource_Memory source(data); + data.destroy(); + + u32bit length = 0; + while(true) + { + ASN1_Tag type_tag, class_tag; + u32bit tag_size = decode_tag(&source, type_tag, class_tag); + if(type_tag == NO_OBJECT) + break; + + u32bit length_size = 0; + u32bit 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 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 * +*************************************************/ +void BER_Decoder::verify_end() const + { + if(!source->end_of_data() || (pushed.type_tag != NO_OBJECT)) + throw Invalid_State("BER_Decoder::verify_end called, but data remains"); + } + +/************************************************* +* Return all the bytes remaining in the source * +*************************************************/ +SecureVector BER_Decoder::get_remaining() + { + SecureVector out; + byte buf; + while(source->read_byte(buf)) + out.append(buf); + return out; + } + +/************************************************* +* Discard all the bytes remaining in the source * +*************************************************/ +void BER_Decoder::discard_remaining() + { + byte buf; + while(source->read_byte(buf)) + ; + } + +/************************************************* +* 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; + + u32bit length = decode_length(source); + next.value.create(length); + if(source->read(next.value, length) != length) + throw BER_Decoding_Error("Value truncated"); + + if(next.type_tag == EOC && next.class_tag == UNIVERSAL) + return get_next_object(); + + return next; + } + +/************************************************* +* 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; + } + +/************************************************* +* BER_Decoder Constructor * +*************************************************/ +BER_Decoder::BER_Decoder(DataSource& src) + { + source = &src; + owns = false; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + } + +/************************************************* +* BER_Decoder Constructor * + *************************************************/ +BER_Decoder::BER_Decoder(const byte data[], u32bit length) + { + source = new DataSource_Memory(data, length); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + } + +/************************************************* +* BER_Decoder Constructor * +*************************************************/ +BER_Decoder::BER_Decoder(const MemoryRegion& data) + { + source = new DataSource_Memory(data); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + } + +/************************************************* +* 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; + } + +/************************************************* +* BER_Decoder Destructor * +*************************************************/ +BER_Decoder::~BER_Decoder() + { + if(owns) + delete source; + source = 0; + } + +} --- botan/ber_dec.h +++ botan/ber_dec.h @@ -0,0 +1,118 @@ +/************************************************* +* BER Decoder Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BER_DECODER_H__ +#define BOTAN_BER_DECODER_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* BER Encoded Object * +*************************************************/ +struct BER_Object + { + ASN1_Tag type_tag, class_tag; + SecureVector value; + }; + +/************************************************* +* BER Decoding Object * +*************************************************/ +class BER_Decoder + { + public: + bool more_items() const; + void verify_end() const; + SecureVector get_remaining(); + void discard_remaining(); + BER_Object get_next_object(); + void push_back(const BER_Object&); + + BER_Decoder(DataSource&); + BER_Decoder(const byte[], u32bit); + BER_Decoder(const MemoryRegion&); + BER_Decoder(const BER_Decoder&); + ~BER_Decoder(); + private: + BER_Decoder& operator=(const BER_Decoder&) { return (*this); } + DataSource* source; + BER_Object pushed; + mutable bool owns; + }; + +/************************************************* +* BER Decoding Functions * +*************************************************/ +namespace BER { + +void decode_null(BER_Decoder&); +void decode(BER_Decoder&, OID&); + +void decode(BER_Decoder&, bool&); +void decode(BER_Decoder&, u32bit&); +void decode(BER_Decoder&, BigInt&); +void decode(BER_Decoder&, MemoryRegion&, ASN1_Tag); + +void decode(BER_Decoder&, bool&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void decode(BER_Decoder&, u32bit&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void decode(BER_Decoder&, BigInt&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void decode(BER_Decoder&, MemoryRegion&, ASN1_Tag, + ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + +BER_Decoder get_subsequence(BER_Decoder&); +BER_Decoder get_subset(BER_Decoder&); + +BER_Decoder get_subsequence(BER_Decoder&, ASN1_Tag, + ASN1_Tag = CONTEXT_SPECIFIC); +BER_Decoder get_subset(BER_Decoder&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + +std::string to_string(const BER_Object&); +bool decode_optional_string(BER_Decoder&, MemoryRegion&, + ASN1_Tag, ASN1_Tag, ASN1_Tag); + +bool maybe_BER(DataSource&); + +/************************************************* +* Decode an OPTIONAL or DEFAULT element * +*************************************************/ +template +bool decode_optional(BER_Decoder& in, T& out, + ASN1_Tag type_tag, ASN1_Tag class_tag, + const T& default_value = T()) + { + BER_Object obj = in.get_next_object(); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + if(class_tag & CONSTRUCTED) + { + BER_Decoder stored_value(obj.value); + BER::decode(stored_value, out); + stored_value.verify_end(); + } + else + { + in.push_back(obj); + BER::decode(in, out, type_tag, class_tag); + } + return true; + } + else + { + out = default_value; + in.push_back(obj); + return false; + } + } + +} + +} + +#endif --- botan/big_base.cpp +++ botan/big_base.cpp @@ -0,0 +1,485 @@ +/************************************************* +* BigInt Base Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#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 u32bit limbs_needed = sizeof(u64bit) / sizeof(word); + + reg.create(2*limbs_needed + 2); + for(u32bit j = 0; j != limbs_needed; j++) + reg[j] = (word)((n >> (j*MP_WORD_BITS)) & MP_WORD_MASK); + } + +/************************************************* +* Construct a BigInt of the specified size * +*************************************************/ +BigInt::BigInt(Sign s, u32bit size) + { + reg.create(size); + signedness = s; + } + +/************************************************* +* Construct a BigInt from a "raw" BigInt * +*************************************************/ +BigInt::BigInt(const BigInt& b) + { + if(b.sig_words()) + { + reg.set(b.data(), b.sig_words()); + set_sign(b.sign()); + } + else + { + reg.create(2); + set_sign(Positive); + } + } + +/************************************************* +* Construct a BigInt from a string * +*************************************************/ +BigInt::BigInt(const std::string& str) + { + Base base = Decimal; + u32bit 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; } + else if(str.length() > markers + 1 && str[markers] == '0') + { markers += 1; base = Octal; } + + *this = decode((const byte*)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[], u32bit length, Base base) + { + set_sign(Positive); + *this = decode(input, length, base); + } + +/************************************************* +* Construct a Random BigInt * +*************************************************/ +BigInt::BigInt(NumberType type, u32bit bits) + { + set_sign(Positive); + if(type == Random && bits) + randomize(bits); + else if(type == Power2) + set_bit(bits); + } + +/************************************************* +* Swap this BigInt with another * +*************************************************/ +void BigInt::swap(BigInt& other) + { + std::swap(reg, other.reg); + std::swap(signedness, other.signedness); + } + +/************************************************* +* Comparison Function * +*************************************************/ +s32bit BigInt::cmp(const BigInt& n, bool check_signs) const + { + if(check_signs) + { + if(n.is_positive() && this->is_negative()) return -1; + if(n.is_negative() && this->is_positive()) return 1; + if(n.is_negative() && this->is_negative()) + return (-bigint_cmp(data(), sig_words(), n.data(), n.sig_words())); + } + return bigint_cmp(data(), sig_words(), n.data(), n.sig_words()); + } + +/************************************************* +* Add n to this number * +*************************************************/ +void BigInt::add(word n) + { + if(!n) return; + word temp = reg[0]; + reg[0] += n; + if(reg[0] > temp) + return; + for(u32bit j = 1; j != size(); j++) + if(++reg[j]) return; + grow_to(2*size()); + reg[size() / 2] = 1; + } + +/************************************************* +* Subtract n from this number * +*************************************************/ +void BigInt::sub(word n) + { + if(!n) return; + word temp = reg[0]; + reg[0] -= n; + if(reg[0] < temp) + return; + for(u32bit j = 1; j != size(); j++) + if(reg[j]--) return; + reg.create(2); + flip_sign(); + reg[0] = n - temp; + } + +/************************************************* +* Prefix Increment Operator * +*************************************************/ +BigInt& BigInt::operator++() + { + if(is_negative()) sub(1); + else add(1); + return (*this); + } + +/************************************************* +* Prefix Decrement Operator * +*************************************************/ +BigInt& BigInt::operator--() + { + if(is_negative()) add(1); + else sub(1); + return (*this); + } + +/************************************************* +* Return word n of this number * +*************************************************/ +word BigInt::word_at(u32bit n) const + { + if(n >= size()) return 0; + else return reg[n]; + } + +/************************************************* +* 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; + } + +/************************************************* +* Return byte n of this number * +*************************************************/ +byte BigInt::byte_at(u32bit n) const + { + const u32bit WORD_BYTES = sizeof(word); + u32bit 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, reg[word_num]); + } + +/************************************************* +* Return bit n of this number * +*************************************************/ +bool BigInt::get_bit(u32bit n) const + { + return ((word_at(n / MP_WORD_BITS) >> (n % MP_WORD_BITS)) & 1); + } + +/************************************************* +* Return nibble n of this number * +*************************************************/ +u32bit BigInt::get_nibble(u32bit n, u32bit nibble_size) const + { + if(nibble_size > 32) + throw Invalid_Argument("BigInt::get_nibble: Nibble size too large"); + + u32bit nibble = 0; + for(s32bit j = (s32bit)nibble_size-1; j >= 0; j--) + { + nibble <<= 1; + if(get_bit(n * nibble_size + j)) + nibble |= 1; + } + return nibble; + } + +/************************************************* +* Set bit number n * +*************************************************/ +void BigInt::set_bit(u32bit n) + { + const u32bit which = n / MP_WORD_BITS; + const word mask = (word)1 << (n % MP_WORD_BITS); + if(which >= size()) grow_to(which + 1); + reg[which] |= mask; + } + +/************************************************* +* Clear bit number n * +*************************************************/ +void BigInt::clear_bit(u32bit n) + { + const u32bit which = n / MP_WORD_BITS; + const word mask = (word)1 << (n % MP_WORD_BITS); + if(which < size()) + reg[which] &= ~mask; + } + +/************************************************* +* Clear all but the lowest n bits * +*************************************************/ +void BigInt::mask_bits(u32bit n) + { + if(n == 0) { clear(); return; } + if(n >= bits()) return; + + const u32bit top_word = n / MP_WORD_BITS; + const word mask = ((word)1 << (n % MP_WORD_BITS)) - 1; + + if(top_word < size()) + for(u32bit j = top_word + 1; j != size(); j++) + reg[j] = 0; + + reg[top_word] &= mask; + } + +/************************************************* +* Count the significant words * +*************************************************/ +u32bit BigInt::sig_words() const + { + const word* x = data(); + u32bit top_set = size(); + + while(top_set >= 4) + { + word sum = x[top_set-1] | x[top_set-2] | x[top_set-3] | x[top_set-4]; + if(sum) break; + else top_set -= 4; + } + while(top_set && (x[top_set-1] == 0)) + top_set--; + return top_set; + } + +/************************************************* +* Count how many bytes are being used * +*************************************************/ +u32bit BigInt::bytes() const + { + return (bits() + 7) / 8; + } + +/************************************************* +* Count how many bits are being used * +*************************************************/ +u32bit BigInt::bits() const + { + if(sig_words() == 0) return 0; + u32bit full_words = sig_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 * +*************************************************/ +u32bit 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 == Octal) + return ((bits() + 2) / 3); + else if(base == Decimal) + return (u32bit)((bits() * LOG_2_BASE_10) + 1); + else + throw Invalid_Argument("Unknown base for BigInt encoding"); + } + +/************************************************* +* Return true if this number is zero * +*************************************************/ +bool BigInt::is_zero() const + { + for(u32bit j = 0; j != size(); j++) + if(reg[j]) return false; + return true; + } + +/************************************************* +* Set the sign * +*************************************************/ +void BigInt::set_sign(Sign s) + { + if(is_zero()) + signedness = Positive; + else + 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; + } + +/************************************************* +* Randomize this number * +*************************************************/ +void BigInt::randomize(u32bit bitsize, RNG_Quality level) + { + set_sign(Positive); + + if(bitsize == 0) + clear(); + else + { + SecureVector array((bitsize + 7) / 8); + Global_RNG::randomize(array, array.size(), level); + if(bitsize % 8) + array[0] &= 0xFF >> (8 - (bitsize % 8)); + array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0); + binary_decode(array, array.size()); + } + } + +/************************************************* +* Encode this number into bytes * +*************************************************/ +void BigInt::binary_encode(byte output[]) const + { + const u32bit sig_bytes = bytes(); + for(u32bit j = 0; j != sig_bytes; j++) + output[sig_bytes-j-1] = byte_at(j); + } + +/************************************************* +* Set this number to the value in buf * +*************************************************/ +void BigInt::binary_decode(const byte buf[], u32bit length) + { + const u32bit WORD_BYTES = sizeof(word); + reg.create(length / WORD_BYTES + 1); + + for(u32bit j = 0; j != length / WORD_BYTES; j++) + { + u32bit top = length - WORD_BYTES*j; + for(u32bit k = WORD_BYTES; k > 0; k--) + reg[j] = (reg[j] << 8) | buf[top - k]; + } + for(u32bit j = 0; j != length % WORD_BYTES; j++) + reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[j]; + } + +/************************************************* +* Generate a random integer * +*************************************************/ +BigInt random_integer(u32bit bits, RNG_Quality level) + { + BigInt x; + x.randomize(bits, level); + return x; + } + +/************************************************* +* Generate a random integer within given range * +*************************************************/ +BigInt random_integer(const BigInt& min, const BigInt& max, RNG_Quality level) + { + BigInt range = max - min; + + if(range <= 0) + throw Invalid_Argument("random_integer: invalid min/max values"); + + return (min + (random_integer(range.bits() + 2, level) % range)); + } + +/************************************************* +* Generate a random safe prime * +*************************************************/ +BigInt random_safe_prime(u32bit bits, RNG_Quality level) + { + if(bits <= 64) + throw Invalid_Argument("random_safe_prime: Can't make a prime of " + + to_string(bits) + " bits"); + + BigInt p; + do + p = (random_prime(bits - 1, level) << 1) + 1; + while(!is_prime(p)); + return p; + } + +} --- botan/big_code.cpp +++ botan/big_code.cpp @@ -0,0 +1,141 @@ +/************************************************* +* BigInt Encoding/Decoding Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#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) + { + SecureVector binary(n.encoded_size(Binary)); + n.binary_encode(binary); + for(u32bit j = 0; j != binary.size(); j++) + Hex_Encoder::encode(binary[j], output + 2*j); + } + else if(base == Octal) + { + BigInt copy = n; + const u32bit output_size = n.encoded_size(Octal); + for(u32bit j = 0; j != output_size; j++) + { + output[output_size - 1 - j] = digit2char(copy % 8); + copy /= 8; + } + } + else if(base == Decimal) + { + BigInt copy = n; + BigInt remainder; + copy.set_sign(Positive); + const u32bit output_size = n.encoded_size(Decimal); + for(u32bit j = 0; j != output_size; j++) + { + divide(copy, 10, copy, remainder); + output[output_size - 1 - j] = digit2char(remainder.word_at(0)); + if(copy.is_zero()) + break; + } + } + else + throw Invalid_Argument("Unknown BigInt encoding method"); + } + +/************************************************* +* Encode a BigInt * +*************************************************/ +SecureVector BigInt::encode(const BigInt& n, Base base) + { + SecureVector output(n.encoded_size(base)); + encode(output, n, base); + if(base != Binary) + for(u32bit j = 0; j != output.size(); j++) + if(output[j] == 0) + output[j] = '0'; + return output; + } + +/************************************************* +* Encode a BigInt, with leading 0s if needed * +*************************************************/ +SecureVector BigInt::encode_1363(const BigInt& n, u32bit bytes) + { + const u32bit n_bytes = n.bytes(); + if(n_bytes > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + const u32bit leading_0s = bytes - n_bytes; + + SecureVector output(bytes); + encode(output + leading_0s, n, Binary); + return output; + } + +/************************************************* +* Decode a BigInt * +*************************************************/ +BigInt BigInt::decode(const MemoryRegion& buf, Base base) + { + return BigInt::decode(buf, buf.size(), base); + } + +/************************************************* +* Decode a BigInt * +*************************************************/ +BigInt BigInt::decode(const byte buf[], u32bit length, Base base) + { + BigInt r; + if(base == Binary) + r.binary_decode(buf, length); + else if(base == Hexadecimal) + { + SecureVector hex; + for(u32bit j = 0; j != length; j++) + if(Hex_Decoder::is_valid(buf[j])) + hex.append(buf[j]); + + u32bit offset = (hex.size() % 2); + SecureVector binary(hex.size() / 2 + offset); + + if(offset) + { + byte temp[2] = { '0', hex[0] }; + binary[0] = Hex_Decoder::decode(temp); + } + + for(u32bit j = offset; j != binary.size(); j++) + binary[j] = Hex_Decoder::decode(hex+2*j-offset); + r.binary_decode(binary, binary.size()); + } + else if(base == Decimal || base == Octal) + { + const u32bit RADIX = ((base == Decimal) ? 10 : 8); + for(u32bit j = 0; j != length; j++) + { + byte x = char2digit(buf[j]); + if(x >= RADIX) + { + if(RADIX == 10) + throw Invalid_Argument("BigInt: Invalid decimal string"); + else + throw Invalid_Argument("BigInt: Invalid octal string"); + } + r = RADIX * r + x; + } + } + else + throw Invalid_Argument("Unknown BigInt decoding method"); + return r; + } + +} --- botan/big_io.cpp +++ botan/big_io.cpp @@ -0,0 +1,52 @@ +/************************************************* +* BigInt Input/Output Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#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) + base = BigInt::Octal; + + if(n == 0) + stream.write("0", 1); + else + { + if(n < 0) + stream.write("-", 1); + SecureVector buffer = BigInt::encode(n, base); + u32bit skip = 0; + while(buffer[skip] == '0' && skip < buffer.size()) + skip++; + stream.write((const char*)buffer.begin() + 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; + } + +} --- botan/big_ops2.cpp +++ botan/big_ops2.cpp @@ -0,0 +1,181 @@ +/************************************************* +* BigInt Assignment Operators Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Addition Operator * +*************************************************/ +BigInt& BigInt::operator+=(const BigInt& n) + { + if((sign() == n.sign())) + { + const u32bit reg_size = std::max(sig_words(), n.sig_words()) + 1; + grow_to(reg_size); + bigint_add2(get_reg(), reg_size-1, n.data(), n.sig_words()); + } + else + (*this) = (*this) + n; + return (*this); + } + +/************************************************* +* Subtraction Operator * +*************************************************/ +BigInt& BigInt::operator-=(const BigInt& n) + { + s32bit relative_size = bigint_cmp(data(), sig_words(), + n.data(), n.sig_words()); + + if(relative_size == 0) + { + if(sign() == n.sign()) + (*this) = 0; + else + (*this) <<= 1; + return (*this); + } + + const u32bit reg_size = std::max(sig_words(), n.sig_words()) + 1; + grow_to(reg_size); + + if(relative_size == -1) + { + if(sign() == n.sign()) + (*this) = (*this) - n; + else + bigint_add2(get_reg(), reg_size-1, n.data(), n.sig_words()); + set_sign(n.reverse_sign()); + } + if(relative_size == 1) + { + if(sign() == n.sign()) + bigint_sub2(get_reg(), sig_words(), n.data(), n.sig_words()); + else + bigint_add2(get_reg(), reg_size-1, n.data(), n.sig_words()); + } + return (*this); + } + +/************************************************* +* Multiplication Operator * +*************************************************/ +BigInt& BigInt::operator*=(const BigInt& n) + { + if(is_zero()) return (*this); + if(n.is_zero()) { (*this) = 0; return (*this); } + + if(sign() != n.sign()) + set_sign(Negative); + else + set_sign(Positive); + + const u32bit words = sig_words(); + const u32bit n_words = n.sig_words(); + + if(words == 1 || n_words == 1) + { + grow_to(words + n_words); + if(n_words == 1) + bigint_linmul2(get_reg(), words, n.word_at(0)); + else + bigint_linmul3(get_reg(), n.data(), n_words, word_at(0)); + return (*this); + } + + BigInt z(sign(), size() + n.size()); + bigint_mul3(z.get_reg(), z.size(), + data(), size(), words, + n.data(), n.size(), n_words); + (*this) = z; + return (*this); + } + +/************************************************* +* Division Operator * +*************************************************/ +BigInt& BigInt::operator/=(const BigInt& n) + { + if(n.sig_words() == 1 && power_of_2(n.word_at(0))) + (*this) >>= (n.bits() - 1); + else + (*this) = (*this) / n; + 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(power_of_2(mod)) + { + word result = (word_at(0) & (mod - 1)); + clear(); + reg.grow_to(2); + reg[0] = result; + return result; + } + + word remainder = 0; + u32bit size = sig_words(); + + for(u32bit j = size; j > 0; j--) + remainder = bigint_modop(remainder, word_at(j-1), mod); + clear(); + reg.grow_to(2); + reg[0] = remainder; + return word_at(0); + } + +/************************************************* +* Left Shift Operator * +*************************************************/ +BigInt& BigInt::operator<<=(u32bit shift) + { + if(shift == 0) return (*this); + const u32bit shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + grow_to(sig_words() + shift_words + (shift_bits ? 1 : 0)); + bigint_shl1(get_reg(), sig_words(), shift_words, shift_bits); + return (*this); + } + +/************************************************* +* Right Shift Operator * +*************************************************/ +BigInt& BigInt::operator>>=(u32bit shift) + { + if(shift == 0) return (*this); + + if(bits() <= shift) + { + (*this) = 0; + return (*this); + } + + const u32bit shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits); + return (*this); + } + +} --- botan/big_ops3.cpp +++ botan/big_ops3.cpp @@ -0,0 +1,172 @@ +/************************************************* +* BigInt Binary Operators Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Addition Operator * +*************************************************/ +BigInt operator+(const BigInt& x, const BigInt& y) + { + if((x.sign() == y.sign())) + { + BigInt z(x.sign(), std::max(x.sig_words(), y.sig_words()) + 1); + bigint_add3(z.get_reg(), x.data(), x.sig_words(), + y.data(), y.sig_words()); + return z; + } + else if(x.is_positive()) + return (x - y.abs()); + else + return (y - x.abs()); + } + +/************************************************* +* Subtraction Operator * +*************************************************/ +BigInt operator-(const BigInt& x, const BigInt& y) + { + s32bit relative_size = bigint_cmp(x.data(), x.sig_words(), + y.data(), y.sig_words()); + if(relative_size == 0 && (x.sign() == y.sign())) return 0; + if(relative_size == 0 && (x.sign() != y.sign())) return (x << 1); + + BigInt z(BigInt::Positive, std::max(x.sig_words(), y.sig_words()) + 1); + + if(relative_size == -1) + { + if(x.sign() == y.sign()) + bigint_sub3(z.get_reg(), y.data(), y.sig_words(), + x.data(), x.sig_words()); + else + bigint_add3(z.get_reg(), x.data(), x.sig_words(), + y.data(), y.sig_words()); + z.set_sign(y.reverse_sign()); + } + if(relative_size == 1) + { + if(x.sign() == y.sign()) + bigint_sub3(z.get_reg(), x.data(), x.sig_words(), + y.data(), y.sig_words()); + else + bigint_add3(z.get_reg(), x.data(), x.sig_words(), + y.data(), y.sig_words()); + z.set_sign(x.sign()); + } + return z; + } + +/************************************************* +* Multiplication Operator * +*************************************************/ +BigInt operator*(const BigInt& x, const BigInt& y) + { + if(x.is_zero() || y.is_zero()) + return 0; + + BigInt::Sign sign = BigInt::Positive; + if(x.sign() != y.sign()) + sign = BigInt::Negative; + + const u32bit x_sw = x.sig_words(); + const u32bit y_sw = y.sig_words(); + + if(x_sw == 1 || y_sw == 1) + { + BigInt z(sign, x_sw + y_sw); + if(x_sw == 1) + bigint_linmul3(z.get_reg(), y.data(), y_sw, x.word_at(0)); + else + bigint_linmul3(z.get_reg(), x.data(), x_sw, y.word_at(0)); + return z; + } + + BigInt z(sign, x.size() + y.size()); + bigint_mul3(z.get_reg(), z.size(), + x.data(), x.size(), x_sw, + y.data(), y.size(), y_sw); + 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(power_of_2(mod)) + return (n.word_at(0) & (mod - 1)); + + word remainder = 0; + u32bit size = n.sig_words(); + + for(u32bit j = size; j > 0; j--) + remainder = bigint_modop(remainder, n.word_at(j-1), mod); + return remainder; + } + +/************************************************* +* Left Shift Operator * +*************************************************/ +BigInt operator<<(const BigInt& x, u32bit shift) + { + if(shift == 0) return x; + const u32bit shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + BigInt y(x.sign(), x.sig_words() + shift_words + (shift_bits ? 1 : 0)); + bigint_shl2(y.get_reg(), x.data(), x.sig_words(), shift_words, shift_bits); + return y; + } + +/************************************************* +* Right Shift Operator * +*************************************************/ +BigInt operator>>(const BigInt& x, u32bit shift) + { + if(shift == 0) return x; + if(x.bits() <= shift) return 0; + + const u32bit shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + BigInt y(x.sign(), x.sig_words() - shift_words); + bigint_shr2(y.get_reg(), x.data(), x.sig_words(), shift_words, shift_bits); + return y; + } + +} --- botan/bigint.h +++ botan/bigint.h @@ -0,0 +1,156 @@ +/************************************************* +* BigInt Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BIGINT_H__ +#define BOTAN_BIGINT_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* BigInt * +*************************************************/ +class BigInt + { + public: + enum Base { Octal = 8, Decimal = 10, Hexadecimal = 16, Binary = 256 }; + enum Sign { Negative = 0, Positive = 1 }; + enum NumberType { Random, Power2 }; + + struct DivideByZero : public Exception + { DivideByZero() : Exception("BigInt divide by zero") {} }; + + BigInt& operator+=(const BigInt&); + BigInt& operator-=(const BigInt&); + + BigInt& operator*=(const BigInt&); + BigInt& operator/=(const BigInt&); + BigInt& operator%=(const BigInt&); + word operator%=(word); + BigInt& operator<<=(u32bit); + BigInt& operator>>=(u32bit); + + BigInt& operator++(); + BigInt& operator--(); + BigInt operator++(int) { BigInt tmp = (*this); ++(*this); return tmp; } + BigInt operator--(int) { BigInt tmp = (*this); --(*this); return tmp; } + + BigInt operator-() const; + bool operator !() const { return (!is_nonzero()); } + + void add(word); + void sub(word); + + s32bit cmp(const BigInt&, bool = true) const; + bool is_even() const { return (get_bit(0) == 0); } + bool is_odd() const { return (get_bit(0) == 1); } + bool is_nonzero() const { return (!is_zero()); } + bool is_zero() const; + + void set_bit(u32bit); + void clear_bit(u32bit); + void mask_bits(u32bit); + + bool get_bit(u32bit) const; + u32bit get_nibble(u32bit, u32bit) const; + byte byte_at(u32bit) const; + word word_at(u32bit) const; + + u32bit to_u32bit() const; + + bool is_negative() const { return (sign() == Negative); } + bool is_positive() const { return (sign() == Positive); } + Sign sign() const { return (signedness); } + Sign reverse_sign() const; + void flip_sign(); + void set_sign(Sign); + BigInt abs() const; + + u32bit size() const { return reg.size(); } + u32bit sig_words() const; + u32bit bytes() const; + u32bit bits() const; + + const word* data() const { return reg.begin(); } + SecureVector& get_reg() { return reg; } + void grow_reg(u32bit n) const { reg.grow_by(n); } + + word& operator[](u32bit index) { return reg[index]; } + word operator[](u32bit index) const { return reg[index]; } + void clear() { reg.clear(); } + + void randomize(u32bit = 0, RNG_Quality = SessionKey); + + void binary_encode(byte[]) const; + void binary_decode(const byte[], u32bit); + u32bit encoded_size(Base = Binary) const; + + static SecureVector encode(const BigInt&, Base = Binary); + static void encode(byte[], const BigInt&, Base = Binary); + static BigInt decode(const byte[], u32bit, Base = Binary); + static BigInt decode(const MemoryRegion&, Base = Binary); + static SecureVector encode_1363(const BigInt&, u32bit); + + void swap(BigInt&); + + BigInt(u64bit = 0); + BigInt(const BigInt&); + BigInt(const std::string&); + BigInt(const byte[], u32bit, Base = Binary); + BigInt(Sign, u32bit); + BigInt(NumberType, u32bit); + private: + friend void modifying_divide(BigInt&, BigInt&, BigInt&); + void grow_to(u32bit n) const { reg.grow_to(n); } + Sign signedness; + SecureVector reg; + }; + +/************************************************* +* Arithmetic Operators * +*************************************************/ +BigInt operator+(const BigInt&, const BigInt&); +BigInt operator-(const BigInt&, const BigInt&); +BigInt operator*(const BigInt&, const BigInt&); +BigInt operator/(const BigInt&, const BigInt&); +BigInt operator%(const BigInt&, const BigInt&); +word operator%(const BigInt&, word); +BigInt operator<<(const BigInt&, u32bit); +BigInt operator>>(const BigInt&, u32bit); + +/************************************************* +* 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 * +*************************************************/ +std::ostream& operator<<(std::ostream&, const BigInt&); +std::istream& operator>>(std::istream&, BigInt&); + +} + +namespace std { + +inline void swap(Botan::BigInt& a, Botan::BigInt& b) { a.swap(b); } + +} + +#endif --- botan/blinding.cpp +++ botan/blinding.cpp @@ -0,0 +1,84 @@ +/************************************************* +* Blinder Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Blinder Constructor * +*************************************************/ +Blinder::Blinder() + { + reducer = 0; + } + +/************************************************* +* Blinder Copy Constructor * +*************************************************/ +Blinder::Blinder(const Blinder& blinder) + { + reducer = 0; + initialize(blinder.e, blinder.d, blinder.n); + } + +/************************************************* +* Blinder Assignment Operator * +*************************************************/ +Blinder& Blinder::operator=(const Blinder& blinder) + { + delete reducer; + reducer = 0; + + if(blinder.reducer) + initialize(blinder.e, blinder.d, blinder.n); + return (*this); + } + +/************************************************* +* Initialize a Blinder object * +*************************************************/ +void Blinder::initialize(const BigInt& e1, const BigInt& d1, const BigInt& n1) + { + if(e1 < 1 || d1 < 1 || n1 < 1) + throw Invalid_Argument("Blinder::initialize: Arguments too small"); + + e = e1; + d = d1; + n = n1; + delete reducer; + reducer = get_reducer(n); + } + +/************************************************* +* Blinder Destructor * +*************************************************/ +Blinder::~Blinder() + { + delete reducer; + } + +/************************************************* +* Blind a number * +*************************************************/ +BigInt Blinder::blind(const BigInt& i) const + { + if(!reducer) 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) return i; + return reducer->multiply(i, d); + } + +} --- botan/blinding.h +++ botan/blinding.h @@ -0,0 +1,37 @@ +/************************************************* +* Blinder Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BLINDER_H__ +#define BOTAN_BLINDER_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Blinding Function Object * +*************************************************/ +class Blinder + { + public: + BigInt blind(const BigInt&) const; + BigInt unblind(const BigInt&) const; + + void initialize(const BigInt&, const BigInt&, const BigInt&); + Blinder& operator=(const Blinder&); + + Blinder(); + Blinder(const Blinder&); + ~Blinder(); + private: + mutable BigInt e, d; + BigInt n; + ModularReducer* reducer; + }; + +} + +#endif --- botan/botan.h +++ botan/botan.h @@ -0,0 +1,13 @@ +/************************************************* +* Basic Interface Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include + --- botan/buf_es.cpp +++ botan/buf_es.cpp @@ -0,0 +1,93 @@ +/************************************************* +* Buffered EntropySource Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Buffered_EntropySource Constructor * +*************************************************/ +Buffered_EntropySource::Buffered_EntropySource() : buffer(256) + { + read_pos = write_pos = 0; + done_slow_poll = false; + } + +/************************************************* +* Fast Poll * +*************************************************/ +u32bit Buffered_EntropySource::fast_poll(byte out[], u32bit length) + { + if(!done_slow_poll) { do_slow_poll(); done_slow_poll = true; } + + do_fast_poll(); + return copy_out(out, length, buffer.size() / 4); + } + +/************************************************* +* Slow Poll * +*************************************************/ +u32bit Buffered_EntropySource::slow_poll(byte out[], u32bit length) + { + do_slow_poll(); + return copy_out(out, length, buffer.size()); + } + +/************************************************* +* Default fast poll operation * +*************************************************/ +void Buffered_EntropySource::do_fast_poll() + { + return do_slow_poll(); + } + +/************************************************* +* Add entropy to the internal buffer * +*************************************************/ +void Buffered_EntropySource::add_bytes(const void* entropy_ptr, u32bit length) + { + const byte* bytes = (const byte*)entropy_ptr; + while(length) + { + u32bit copied = std::min(length, buffer.size() - write_pos); + xor_buf(buffer + write_pos, bytes, copied); + bytes += copied; + length -= copied; + write_pos = (write_pos + copied) % buffer.size(); + } + } + +/************************************************* +* Add entropy to the internal buffer * +*************************************************/ +void Buffered_EntropySource::add_bytes(u64bit entropy) + { + add_bytes((const void*)&entropy, 8); + } + +/************************************************* +* Add entropy to the internal buffer * +*************************************************/ +void Buffered_EntropySource::add_timestamp() + { + add_bytes(system_clock()); + } + +/************************************************* +* Take entropy from the internal buffer * +*************************************************/ +u32bit Buffered_EntropySource::copy_out(byte out[], u32bit length, + u32bit max_read) + { + length = std::min(length, max_read); + u32bit copied = std::min(length, buffer.size() - read_pos); + xor_buf(out, buffer + read_pos, copied); + read_pos = (read_pos + copied) % buffer.size(); + return copied; + } + +} --- botan/buf_es.h +++ botan/buf_es.h @@ -0,0 +1,39 @@ +/************************************************* +* Buffered EntropySource Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BUFFERED_ES_H__ +#define BOTAN_BUFFERED_ES_H__ + +#include + +namespace Botan { + +/************************************************* +* Buffered EntropySource * +*************************************************/ +class Buffered_EntropySource : public EntropySource + { + public: + u32bit slow_poll(byte[], u32bit); + u32bit fast_poll(byte[], u32bit); + protected: + Buffered_EntropySource(); + u32bit copy_out(byte[], u32bit, u32bit); + + void add_bytes(const void*, u32bit); + void add_bytes(u64bit); + void add_timestamp(); + + virtual void do_slow_poll() = 0; + virtual void do_fast_poll(); + private: + SecureVector buffer; + u32bit write_pos, read_pos; + bool done_slow_poll; + }; + +} + +#endif --- botan/buf_filt.cpp +++ botan/buf_filt.cpp @@ -0,0 +1,67 @@ +/************************************************* +* Buffering Filter Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Buffering_Filter Constructor * +*************************************************/ +Buffering_Filter::Buffering_Filter(u32bit b, u32bit i) : INITIAL_BLOCK_SIZE(i), + BLOCK_SIZE(b) + { + initial_block_pos = block_pos = 0; + initial.create(INITIAL_BLOCK_SIZE); + block.create(BLOCK_SIZE); + } + +/************************************************* +* Reset the Buffering Filter * +*************************************************/ +void Buffering_Filter::end_msg() + { + if(initial_block_pos != INITIAL_BLOCK_SIZE) + throw Exception("Buffering_Filter: Not enough data for first block"); + final_block(block, block_pos); + initial_block_pos = block_pos = 0; + initial.clear(); + block.clear(); + } + +/************************************************* +* Buffer input into blocks * +*************************************************/ +void Buffering_Filter::write(const byte input[], u32bit length) + { + if(initial_block_pos != INITIAL_BLOCK_SIZE) + { + u32bit copied = std::min(INITIAL_BLOCK_SIZE - initial_block_pos, length); + initial.copy(initial_block_pos, input, copied); + input += copied; + length -= copied; + initial_block_pos += copied; + if(initial_block_pos == INITIAL_BLOCK_SIZE) + initial_block(initial); + } + block.copy(block_pos, input, length); + if(block_pos + length >= BLOCK_SIZE) + { + main_block(block); + input += (BLOCK_SIZE - block_pos); + length -= (BLOCK_SIZE - block_pos); + while(length >= BLOCK_SIZE) + { + main_block(input); + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + } + block.copy(input, length); + block_pos = 0; + } + block_pos += length; + } + +} --- botan/buf_filt.h +++ botan/buf_filt.h @@ -0,0 +1,35 @@ +/************************************************* +* Buffering Filter Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BUFFERING_FILTER_H__ +#define BOTAN_BUFFERING_FILTER_H__ + +#include + +namespace Botan { + +/************************************************* +* Buffering Filter * +*************************************************/ +class Buffering_Filter : public Filter + { + public: + void write(const byte[], u32bit); + virtual void end_msg(); + Buffering_Filter(u32bit, u32bit = 0); + virtual ~Buffering_Filter() {} + protected: + virtual void initial_block(const byte[]) {} + virtual void main_block(const byte[]) = 0; + virtual void final_block(const byte[], u32bit) = 0; + private: + const u32bit INITIAL_BLOCK_SIZE, BLOCK_SIZE; + SecureVector initial, block; + u32bit initial_block_pos, block_pos; + }; + +} + +#endif --- botan/cbc.cpp +++ botan/cbc.cpp @@ -0,0 +1,155 @@ +/************************************************* +* CBC Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* CBC Encryption Constructor * +*************************************************/ +CBC_Encryption::CBC_Encryption(const std::string& cipher_name, + const std::string& padding_name) : + BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)), + padder(get_bc_pad(padding_name)) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + } + +/************************************************* +* CBC Encryption Constructor * +*************************************************/ +CBC_Encryption::CBC_Encryption(const std::string& cipher_name, + const std::string& padding_name, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)), + padder(get_bc_pad(padding_name)) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + set_key(key); + set_iv(iv); + } + +/************************************************* +* Encrypt in CBC mode * +*************************************************/ +void CBC_Encryption::write(const byte input[], u32bit length) + { + while(length) + { + u32bit xored = std::min(BLOCK_SIZE - position, length); + xor_buf(state + position, input, xored); + input += xored; + length -= xored; + position += xored; + if(position == BLOCK_SIZE) + { + cipher->encrypt(state); + send(state, BLOCK_SIZE); + position = 0; + } + } + } + +/************************************************* +* Finish encrypting in CBC mode * +*************************************************/ +void CBC_Encryption::end_msg() + { + SecureVector padding(BLOCK_SIZE); + padder->pad(padding, padding.size(), position); + write(padding, padder->pad_bytes(BLOCK_SIZE, position)); + if(position != 0) + throw Exception(name() + ": Did not pad to full blocksize"); + } + +/************************************************* +* Return a CBC mode name * +*************************************************/ +std::string CBC_Encryption::name() const + { + return (cipher->name() + "/" + mode_name + "/" + padder->name()); + } + +/************************************************* +* CBC Decryption Constructor * +*************************************************/ +CBC_Decryption::CBC_Decryption(const std::string& cipher_name, + const std::string& padding_name) : + BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)), + padder(get_bc_pad(padding_name)) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + temp.create(BLOCK_SIZE); + } + +/************************************************* +* CBC Decryption Constructor * +*************************************************/ +CBC_Decryption::CBC_Decryption(const std::string& cipher_name, + const std::string& padding_name, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)), + padder(get_bc_pad(padding_name)) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + temp.create(BLOCK_SIZE); + set_key(key); + set_iv(iv); + } + +/************************************************* +* Decrypt in CBC mode * +*************************************************/ +void CBC_Decryption::write(const byte input[], u32bit length) + { + while(length) + { + if(position == BLOCK_SIZE) + { + cipher->decrypt(buffer, temp); + xor_buf(temp, state, BLOCK_SIZE); + send(temp, BLOCK_SIZE); + state = buffer; + position = 0; + } + u32bit added = std::min(BLOCK_SIZE - position, length); + buffer.copy(position, input, added); + input += added; + length -= added; + position += added; + } + } + +/************************************************* +* Finish decrypting in CBC mode * +*************************************************/ +void CBC_Decryption::end_msg() + { + if(position != BLOCK_SIZE) + throw Decoding_Error(name()); + cipher->decrypt(buffer, temp); + xor_buf(temp, state, BLOCK_SIZE); + send(temp, padder->unpad(temp, BLOCK_SIZE)); + state = buffer; + position = 0; + } + +/************************************************* +* Return a CBC mode name * +*************************************************/ +std::string CBC_Decryption::name() const + { + return (cipher->name() + "/" + mode_name + "/" + padder->name()); + } + +} --- botan/cbc.h +++ botan/cbc.h @@ -0,0 +1,49 @@ +/************************************************* +* CBC Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CBC_H__ +#define BOTAN_CBC_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* CBC Encryption * +*************************************************/ +class CBC_Encryption : public BlockCipherMode + { + public: + CBC_Encryption(const std::string&, const std::string&); + CBC_Encryption(const std::string&, const std::string&, + const SymmetricKey&, const InitializationVector&); + private: + std::string name() const; + void write(const byte[], u32bit); + void end_msg(); + const BlockCipherModePaddingMethod* padder; + }; + +/************************************************* +* CBC Decryption * +*************************************************/ +class CBC_Decryption : public BlockCipherMode + { + public: + CBC_Decryption(const std::string&, const std::string&); + CBC_Decryption(const std::string&, const std::string&, + const SymmetricKey&, const InitializationVector&); + private: + std::string name() const; + void write(const byte[], u32bit); + void end_msg(); + const BlockCipherModePaddingMethod* padder; + SecureVector temp; + }; + +} + +#endif --- botan/certstor.h +++ botan/certstor.h @@ -0,0 +1,37 @@ +/************************************************* +* Certificate Store Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CERT_STORE_H__ +#define BOTAN_CERT_STORE_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Certificate Store Interface * +*************************************************/ +class Certificate_Store + { + public: + virtual std::vector + by_SKID(const MemoryRegion&) const = 0; + + virtual std::vector by_name(const std::string&) const; + virtual std::vector by_email(const std::string&) const; + virtual std::vector by_dn(const X509_DN&) const; + + virtual std::vector + get_crls_for(const X509_Certificate&) const; + + virtual Certificate_Store* clone() const = 0; + + virtual ~Certificate_Store() {} + }; + +} + +#endif --- botan/certstore.cpp +++ botan/certstore.cpp @@ -0,0 +1,46 @@ +/************************************************* +* Certificate Store Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Search by name * +*************************************************/ +std::vector +Certificate_Store::by_name(const std::string&) const + { + return std::vector(); + } + +/************************************************* +* Search by email * +*************************************************/ +std::vector +Certificate_Store::by_email(const std::string&) const + { + return std::vector(); + } + +/************************************************* +* Search by X.500 distinguished name * +*************************************************/ +std::vector +Certificate_Store::by_dn(const X509_DN&) const + { + return std::vector(); + } + +/************************************************* +* Find any CRLs that might be useful * +*************************************************/ +std::vector +Certificate_Store::get_crls_for(const X509_Certificate&) const + { + return std::vector(); + } + +} --- botan/cfb.cpp +++ botan/cfb.cpp @@ -0,0 +1,139 @@ +/************************************************* +* CFB Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Check the feedback size * +*************************************************/ +void check_feedback(u32bit BLOCK_SIZE, u32bit FEEDBACK_SIZE, u32bit bits, + const std::string& name) + { + if(FEEDBACK_SIZE == 0 || FEEDBACK_SIZE > BLOCK_SIZE || bits % 8 != 0) + throw Invalid_Argument(name + ": Invalid feedback size " + + to_string(bits)); + } + +} + +/************************************************* +* CFB Encryption Constructor * +*************************************************/ +CFB_Encryption::CFB_Encryption(const std::string& cipher_name, + u32bit fback_bits) : + BlockCipherMode(cipher_name, "CFB", block_size_of(cipher_name), 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8: BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + } + +/************************************************* +* CFB Encryption Constructor * +*************************************************/ +CFB_Encryption::CFB_Encryption(const std::string& cipher_name, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit fback_bits) : + BlockCipherMode(cipher_name, "CFB", block_size_of(cipher_name), 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8: BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + set_key(key); + set_iv(iv); + } + +/************************************************* +* Encrypt data in CFB mode * +*************************************************/ +void CFB_Encryption::write(const byte input[], u32bit length) + { + while(length) + { + u32bit xored = std::min(FEEDBACK_SIZE - position, length); + xor_buf(buffer + position, input, xored); + send(buffer + position, xored); + input += xored; + length -= xored; + position += xored; + if(position == FEEDBACK_SIZE) + feedback(); + } + } + +/************************************************* +* Do the feedback * +*************************************************/ +void CFB_Encryption::feedback() + { + for(u32bit j = 0; j != BLOCK_SIZE - FEEDBACK_SIZE; j++) + state[j] = state[j + FEEDBACK_SIZE]; + state.copy(BLOCK_SIZE - FEEDBACK_SIZE, buffer, FEEDBACK_SIZE); + cipher->encrypt(state, buffer); + position = 0; + } + +/************************************************* +* CFB Decryption Constructor * +*************************************************/ +CFB_Decryption::CFB_Decryption(const std::string& cipher_name, + u32bit fback_bits) : + BlockCipherMode(cipher_name, "CFB", block_size_of(cipher_name), 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8 : BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + } + +/************************************************* +* CFB Decryption Constructor * +*************************************************/ +CFB_Decryption::CFB_Decryption(const std::string& cipher_name, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit fback_bits) : + BlockCipherMode(cipher_name, "CFB", block_size_of(cipher_name), 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8 : BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + set_key(key); + set_iv(iv); + } + +/************************************************* +* Decrypt data in CFB mode * +*************************************************/ +void CFB_Decryption::write(const byte input[], u32bit length) + { + while(length) + { + u32bit xored = std::min(FEEDBACK_SIZE - position, length); + xor_buf(buffer + position, input, xored); + send(buffer + position, xored); + buffer.copy(position, input, xored); + input += xored; + length -= xored; + position += xored; + if(position == FEEDBACK_SIZE) + feedback(); + } + } + +/************************************************* +* Do the feedback * +*************************************************/ +void CFB_Decryption::feedback() + { + for(u32bit j = 0; j != BLOCK_SIZE - FEEDBACK_SIZE; j++) + state[j] = state[j + FEEDBACK_SIZE]; + state.copy(BLOCK_SIZE - FEEDBACK_SIZE, buffer, FEEDBACK_SIZE); + cipher->encrypt(state, buffer); + position = 0; + } + +} --- botan/cfb.h +++ botan/cfb.h @@ -0,0 +1,45 @@ +/************************************************* +* CFB Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CFB_H__ +#define BOTAN_CFB_H__ + +#include + +namespace Botan { + +/************************************************* +* CFB Encryption * +*************************************************/ +class CFB_Encryption : public BlockCipherMode + { + public: + CFB_Encryption(const std::string&, u32bit = 0); + CFB_Encryption(const std::string&, const SymmetricKey&, + const InitializationVector&, u32bit = 0); + private: + void write(const byte[], u32bit); + void feedback(); + const u32bit FEEDBACK_SIZE; + }; + +/************************************************* +* CFB Decryption * +*************************************************/ +class CFB_Decryption : public BlockCipherMode + { + public: + CFB_Decryption(const std::string&, u32bit = 0); + CFB_Decryption(const std::string&, const SymmetricKey&, + const InitializationVector&, u32bit = 0); + private: + void write(const byte[], u32bit); + void feedback(); + const u32bit FEEDBACK_SIZE; + }; + +} + +#endif --- botan/charset.cpp +++ botan/charset.cpp @@ -0,0 +1,108 @@ +/************************************************* +* Character Set Handling Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Return the lower-case representation * +*************************************************/ +char to_lower(char c) + { + return tolower((unsigned char)c); + } + +/************************************************* +* Convert from local charset to ISO 8859-1 * +*************************************************/ +std::string local2iso(const std::string& str) + { + return str; + } + +/************************************************* +* Convert from ISO 8859-1 to local charset * +*************************************************/ +std::string iso2local(const std::string& str) + { + return str; + } + +/************************************************* +* Hex Encoder Lookup Tables * +*************************************************/ +const byte Hex_Encoder::BIN_TO_HEX_UPPER[16] = { +0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, +0x44, 0x45, 0x46 }; + +const byte Hex_Encoder::BIN_TO_HEX_LOWER[16] = { +0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, +0x64, 0x65, 0x66 }; + +/************************************************* +* Base64 Encoder Lookup Table * +*************************************************/ +const byte Base64_Encoder::BIN_TO_BASE64[64] = { +0x41, 0x42, 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, 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, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F }; + +/************************************************* +* Hex Decoder Lookup Table * +*************************************************/ +const byte Hex_Decoder::HEX_TO_BIN[256] = { +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, +0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + +/************************************************* +* Base64 Decoder Lookup Table * +*************************************************/ +const byte Base64_Decoder::BASE64_TO_BIN[256] = { +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, 0x34, 0x35, 0x36, 0x37, +0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +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, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 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, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + +} --- botan/conf.cpp +++ botan/conf.cpp @@ -0,0 +1,176 @@ +/************************************************* +* Configuration Handling Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace Config { + +namespace { + +std::map options; +Mutex* options_lock = 0; + +/************************************************* +* Parse and compute an arithmetic expression * +*************************************************/ +u32bit parse_expr(const std::string& expr) + { + const bool have_add = (expr.find('+') != std::string::npos); + const bool have_mul = (expr.find('*') != std::string::npos); + + if(have_add) + { + std::vector sub_expr = split_on(expr, '+'); + u32bit result = 0; + for(u32bit j = 0; j != sub_expr.size(); j++) + result += parse_expr(sub_expr[j]); + return result; + } + else if(have_mul) + { + std::vector sub_expr = split_on(expr, '*'); + u32bit result = 1; + for(u32bit j = 0; j != sub_expr.size(); j++) + result *= parse_expr(sub_expr[j]); + return result; + } + else + return to_u32bit(expr); + } + +} + +/************************************************* +* Set an option * +*************************************************/ +void set(const std::string& name, const std::string& value, bool overwrite) + { + const bool have_it = ((get_string(name) == "") ? false : true); + + initialize_mutex(options_lock); + Mutex_Holder lock(options_lock); + + if(overwrite || !have_it) + options[name] = value; + } + +/************************************************* +* Get the value of an option as a string * +*************************************************/ +std::string get_string(const std::string& name) + { + initialize_mutex(options_lock); + Mutex_Holder lock(options_lock); + + std::map::const_iterator i = options.find(name); + if(i != options.end()) + return i->second; + return ""; + } + +/************************************************* +* Get the value as a list of strings * +*************************************************/ +std::vector get_list(const std::string& name) + { + return split_on(get_string(name), ':'); + } + +/************************************************* +* Get the value as a u32bit * +*************************************************/ +u32bit get_u32bit(const std::string& name) + { + return parse_expr(get_string(name)); + } + +/************************************************* +* Get the value as a time * +*************************************************/ +u32bit get_time(const std::string& name) + { + const std::string timespec = get_string(name); + if(timespec == "") + return 0; + + const char suffix = timespec[timespec.size()-1]; + std::string value = timespec.substr(0, timespec.size()-1); + + u32bit scale = 1; + + if(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("Config::get_time: Unknown time value " + value); + + return scale * to_u32bit(value); + } + +/************************************************* +* Get the value as a boolean * +*************************************************/ +bool get_bool(const std::string& name) + { + const std::string value = get_string(name); + if(value == "0" || value == "false") + return false; + if(value == "1" || value == "true") + return true; + throw Decoding_Error("Config::get_bool: Unknown boolean value " + value); + } + +/************************************************* +* Choose the signature format for a PK algorithm * +*************************************************/ +void choose_sig_format(const std::string& algo_name, std::string& padding, + Signature_Format& format) + { + std::string dummy; + choose_sig_format(algo_name, padding, dummy, format); + } + +/************************************************* +* Choose the signature format for a PK algorithm * +*************************************************/ +void choose_sig_format(const std::string& algo_name, std::string& padding, + std::string& hash, Signature_Format& format) + { + if(algo_name == "RSA") + { + hash = deref_alias(get_string("x509/ca/rsa_hash")); + if(hash == "") + throw Invalid_State("No value set for x509/ca/rsa_hash"); + + padding = "EMSA3(" + hash + ")"; + format = IEEE_1363; + } + else if(algo_name == "DSA") + { + hash = deref_alias("SHA-1"); + padding = "EMSA1(" + hash + ")"; + format = DER_SEQUENCE; + } + else + throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + } + +} + +} --- botan/conf.h +++ botan/conf.h @@ -0,0 +1,49 @@ +/************************************************* +* Configuration Handling Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_POLICY_CONF_H__ +#define BOTAN_POLICY_CONF_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace Config { + +/************************************************* +* Set an option * +*************************************************/ +void set(const std::string&, const std::string&, bool = true); + +/************************************************* +* Get the value of some option * +*************************************************/ +std::vector get_list(const std::string&); +std::string get_string(const std::string&); +u32bit get_u32bit(const std::string&); +u32bit get_time(const std::string&); +bool get_bool(const std::string&); + +/************************************************* +* Choose the signature format for a PK algorithm * +*************************************************/ +void choose_sig_format(const std::string&, std::string&, Signature_Format&); +void choose_sig_format(const std::string&, std::string&, std::string&, + Signature_Format&); + +/************************************************* +* Load a configuration file * +*************************************************/ +void load(const std::string&); + +} + +} + +#endif --- botan/config.h +++ botan/config.h @@ -0,0 +1,25 @@ +/************************************************* +* Configuration Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CONFIG_H__ +#define BOTAN_CONFIG_H__ + +#define BOTAN_MP_WORD_BITS 32 +#define BOTAN_DEFAULT_BUFFER_SIZE 4096 +#define BOTAN_VECTOR_OVER_ALLOCATE 4 +#define BOTAN_GZIP_OS_CODE 255 + +#if defined(_MSC_VER) + #pragma warning(disable: 4250 4290) +#endif + +#define BOTAN_VERSION_MAJOR 1 +#define BOTAN_VERSION_MINOR 4 +#define BOTAN_VERSION_PATCH 3 + +#define BOTAN_EXT_COMPRESSOR_GZIP +#define BOTAN_EXT_COMPRESSOR_ZLIB + +#endif --- botan/crc32.cpp +++ botan/crc32.cpp @@ -0,0 +1,100 @@ +/************************************************* +* CRC32 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Update a CRC32 Checksum * +*************************************************/ +void CRC32::add_data(const byte input[], u32bit 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(u32bit j = 0; j != length; j++) + tmp = TABLE[(tmp ^ input[j]) & 0xFF] ^ (tmp >> 8); + + crc = tmp; + } + +/************************************************* +* Finalize a CRC32 Checksum * +*************************************************/ +void CRC32::final_result(byte output[]) + { + crc ^= 0xFFFFFFFF; + for(u32bit j = 0; j != 4; j++) + output[j] = get_byte(j, crc); + clear(); + } + +} --- botan/crc32.h +++ botan/crc32.h @@ -0,0 +1,32 @@ +/************************************************* +* CRC32 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CRC32_H__ +#define BOTAN_CRC32_H__ + +#include + +namespace Botan { + +/************************************************* +* CRC32 * +*************************************************/ +class CRC32 : public HashFunction + { + public: + void clear() throw() { crc = 0xFFFFFFFF; } + std::string name() const { return "CRC32"; } + HashFunction* clone() const { return new CRC32; } + CRC32() : HashFunction(4) { clear(); } + ~CRC32() { clear(); } + private: + void add_data(const byte[], u32bit); + void final_result(byte[]); + u32bit crc; + }; + +} + +#endif --- botan/crl_ent.cpp +++ botan/crl_ent.cpp @@ -0,0 +1,153 @@ +/************************************************* +* CRL Entry Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Create a CRL_Entry * +*************************************************/ +CRL_Entry::CRL_Entry() + { + reason = UNSPECIFIED; + } + +/************************************************* +* Create a CRL_Entry * +*************************************************/ +CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) + { + serial = cert.serial_number(); + time = X509_Time(system_time()); + reason = why; + } + +/************************************************* +* Compare two CRL_Entrys for equality * +*************************************************/ +bool operator==(const CRL_Entry& a1, const CRL_Entry& a2) + { + if(a1.serial != a2.serial) + return false; + if(a1.time != a2.time) + return false; + if(a1.reason != a2.reason) + return false; + return true; + } + +/************************************************* +* Compare two CRL_Entrys for inequality * +*************************************************/ +bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2) + { + return !(a1 == a2); + } + +/************************************************* +* Compare two CRL_Entrys * +*************************************************/ +bool operator<(const CRL_Entry& a1, const CRL_Entry& a2) + { + return (a1.time.cmp(a2.time) < 0); + } + +namespace DER { + +/************************************************* +* DER encode an CRL_Entry * +*************************************************/ +void encode(DER_Encoder& encoder, const CRL_Entry& crl_ent) + { + encoder.start_sequence(); + DER::encode(encoder, BigInt::decode(crl_ent.serial, crl_ent.serial.size())); + DER::encode(encoder, crl_ent.time); + + encoder.start_sequence(); + if(crl_ent.reason != UNSPECIFIED) + { + DER_Encoder v2_ext; + DER::encode(v2_ext, (u32bit)crl_ent.reason, ENUMERATED, UNIVERSAL); + DER::encode(encoder, + Extension("X509v3.ReasonCode", v2_ext.get_contents())); + } + encoder.end_sequence(); + + encoder.end_sequence(); + } + +} + +namespace BER { + +namespace { + +/************************************************* +* Decode a CRL entry extension * +*************************************************/ +void handle_crl_entry_extension(CRL_Entry& crl_ent, const Extension& extn) + { + BER_Decoder value(extn.value); + + if(extn.oid == OIDS::lookup("X509v3.ReasonCode")) + { + u32bit reason_code; + BER::decode(value, reason_code, ENUMERATED, UNIVERSAL); + crl_ent.reason = CRL_Code(reason_code); + } + else + { + if(extn.critical) + { + std::string action = Config::get_string("x509/crl/unknown_critical"); + if(action == "throw") + throw Decoding_Error("Unknown critical CRL entry extension " + + extn.oid.as_string()); + else if(action != "ignore") + throw Invalid_Argument("Bad value of x509/crl/unknown_critical: " + + action); + } + return; + } + + value.verify_end(); + } + +} + +/************************************************* +* Decode a BER encoded CRL_Entry * +*************************************************/ +void decode(BER_Decoder& source, CRL_Entry& crl_ent) + { + BigInt serial_number; + + BER_Decoder sequence = BER::get_subsequence(source); + BER::decode(sequence, serial_number); + crl_ent.serial = BigInt::encode(serial_number); + BER::decode(sequence, crl_ent.time); + + if(sequence.more_items()) + { + BER_Decoder crl_entry_exts = BER::get_subsequence(sequence); + while(crl_entry_exts.more_items()) + { + Extension extn; + BER::decode(crl_entry_exts, extn); + handle_crl_entry_extension(crl_ent, extn); + } + } + + sequence.verify_end(); + } + +} + +} --- botan/crl_ent.h +++ botan/crl_ent.h @@ -0,0 +1,53 @@ +/************************************************* +* CRL Entry Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CRL_ENTRY_H__ +#define BOTAN_CRL_ENTRY_H__ + +#include + +namespace Botan { + +/************************************************* +* CRL Entry * +*************************************************/ +class CRL_Entry + { + public: + MemoryVector serial; + X509_Time time; + CRL_Code reason; + CRL_Entry(); + CRL_Entry(const X509_Certificate&, CRL_Code = UNSPECIFIED); + }; + +/************************************************* +* Comparison Operations * +*************************************************/ +bool operator==(const CRL_Entry&, const CRL_Entry&); +bool operator!=(const CRL_Entry&, const CRL_Entry&); +bool operator<(const CRL_Entry&, const CRL_Entry&); + +/************************************************* +* DER Encoding Functions * +*************************************************/ +namespace DER { + +void encode(DER_Encoder&, const CRL_Entry&); + +} + +/************************************************* +* BER Decoding Functions * +*************************************************/ +namespace BER { + +void decode(BER_Decoder&, CRL_Entry&); + +} + +} + +#endif --- botan/ctr.cpp +++ botan/ctr.cpp @@ -0,0 +1,72 @@ +/************************************************* +* CTR Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* CTR-BE Constructor * +*************************************************/ +CTR_BE::CTR_BE(const std::string& cipher_name) : + BlockCipherMode(cipher_name, "CTR-BE", block_size_of(cipher_name), 1) + { + } + +/************************************************* +* CTR-BE Constructor * +*************************************************/ +CTR_BE::CTR_BE(const std::string& cipher_name, const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(cipher_name, "CTR-BE", block_size_of(cipher_name), 1) + { + set_key(key); + set_iv(iv); + } + +/************************************************* +* CTR-BE Encryption/Decryption * +*************************************************/ +void CTR_BE::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer + position, input, copied); + send(buffer + position, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + increment_counter(); + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + increment_counter(); + } + + xor_buf(buffer + position, input, length); + send(buffer + position, length); + position += length; + } + +/************************************************* +* Increment the counter and update the buffer * +*************************************************/ +void CTR_BE::increment_counter() + { + for(s32bit j = BLOCK_SIZE - 1; j >= 0; j--) + if(++state[j]) + break; + cipher->encrypt(state, buffer); + position = 0; + } + +} --- botan/ctr.h +++ botan/ctr.h @@ -0,0 +1,29 @@ +/************************************************* +* CTR Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CTR_H__ +#define BOTAN_CTR_H__ + +#include + +namespace Botan { + +/************************************************* +* CTR-BE Mode * +*************************************************/ +class CTR_BE : public BlockCipherMode + { + public: + CTR_BE(const std::string&); + CTR_BE(const std::string&, + const SymmetricKey&, const InitializationVector&); + private: + void write(const byte[], u32bit); + void increment_counter(); + }; + +} + +#endif --- botan/cts.cpp +++ botan/cts.cpp @@ -0,0 +1,173 @@ +/************************************************* +* CTS Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* CTS Encryption Constructor * +*************************************************/ +CTS_Encryption::CTS_Encryption(const std::string& cipher_name) : + BlockCipherMode(cipher_name, "CTS", block_size_of(cipher_name), 0, 2) + { + } + +/************************************************* +* CTS Encryption Constructor * +*************************************************/ +CTS_Encryption::CTS_Encryption(const std::string& cipher_name, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(cipher_name, "CTS", block_size_of(cipher_name), 0, 2) + { + set_key(key); + set_iv(iv); + } + +/************************************************* +* Encrypt a block * +*************************************************/ +void CTS_Encryption::encrypt(const byte block[]) + { + xor_buf(state, block, BLOCK_SIZE); + cipher->encrypt(state); + send(state, BLOCK_SIZE); + } + +/************************************************* +* Encrypt in CTS mode * +*************************************************/ +void CTS_Encryption::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BUFFER_SIZE - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + encrypt(buffer); + if(length > BLOCK_SIZE) + { + encrypt(buffer + BLOCK_SIZE); + while(length > 2*BLOCK_SIZE) + { + encrypt(input); + length -= BLOCK_SIZE; + input += BLOCK_SIZE; + } + position = 0; + } + else + { + copy_mem(buffer.begin(), buffer + BLOCK_SIZE, BLOCK_SIZE); + position = BLOCK_SIZE; + } + buffer.copy(position, input, length); + position += length; + } + +/************************************************* +* Finish encrypting in CTS mode * +*************************************************/ +void CTS_Encryption::end_msg() + { + if(position < BLOCK_SIZE + 1) + throw Exception("CTS_Encryption: insufficient data to encrypt"); + xor_buf(state, buffer, BLOCK_SIZE); + cipher->encrypt(state); + SecureVector cn = state; + clear_mem(buffer + position, BUFFER_SIZE - position); + encrypt(buffer + BLOCK_SIZE); + send(cn, position - BLOCK_SIZE); + } + +/************************************************* +* CTS Decryption Constructor * +*************************************************/ +CTS_Decryption::CTS_Decryption(const std::string& cipher_name) : + BlockCipherMode(cipher_name, "CTS", block_size_of(cipher_name), 0, 2) + { + temp.create(BLOCK_SIZE); + } + +/************************************************* +* CTS Decryption Constructor * +*************************************************/ +CTS_Decryption::CTS_Decryption(const std::string& cipher_name, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(cipher_name, "CTS", block_size_of(cipher_name), 0, 2) + { + temp.create(BLOCK_SIZE); + set_key(key); + set_iv(iv); + } + +/************************************************* +* Decrypt a block * +*************************************************/ +void CTS_Decryption::decrypt(const byte block[]) + { + cipher->decrypt(block, temp); + xor_buf(temp, state, BLOCK_SIZE); + send(temp, BLOCK_SIZE); + state.copy(block, BLOCK_SIZE); + } + +/************************************************* +* Decrypt in CTS mode * +*************************************************/ +void CTS_Decryption::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BUFFER_SIZE - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + decrypt(buffer); + if(length > BLOCK_SIZE) + { + decrypt(buffer + BLOCK_SIZE); + while(length > 2*BLOCK_SIZE) + { + decrypt(input); + length -= BLOCK_SIZE; + input += BLOCK_SIZE; + } + position = 0; + } + else + { + copy_mem(buffer.begin(), buffer + BLOCK_SIZE, BLOCK_SIZE); + position = BLOCK_SIZE; + } + buffer.copy(position, input, length); + position += length; + } + +/************************************************* +* Finish decrypting in CTS mode * +*************************************************/ +void CTS_Decryption::end_msg() + { + cipher->decrypt(buffer, temp); + xor_buf(temp, buffer + BLOCK_SIZE, position - BLOCK_SIZE); + SecureVector xn = temp; + copy_mem(buffer + position, xn + (position - BLOCK_SIZE), + BUFFER_SIZE - position); + cipher->decrypt(buffer + BLOCK_SIZE, temp); + xor_buf(temp, state, BLOCK_SIZE); + send(temp, BLOCK_SIZE); + send(xn, position - BLOCK_SIZE); + } + +} --- botan/cts.h +++ botan/cts.h @@ -0,0 +1,46 @@ +/************************************************* +* CTS Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CTS_H__ +#define BOTAN_CTS_H__ + +#include + +namespace Botan { + +/************************************************* +* CTS Encryption * +*************************************************/ +class CTS_Encryption : public BlockCipherMode + { + public: + CTS_Encryption(const std::string&); + CTS_Encryption(const std::string&, + const SymmetricKey&, const InitializationVector&); + private: + void write(const byte[], u32bit); + void end_msg(); + void encrypt(const byte[]); + }; + +/************************************************* +* CTS Decryption * +*************************************************/ +class CTS_Decryption : public BlockCipherMode + { + public: + CTS_Decryption(const std::string&); + CTS_Decryption(const std::string&, + const SymmetricKey&, const InitializationVector&); + private: + void write(const byte[], u32bit); + void end_msg(); + void decrypt(const byte[]); + SecureVector temp; + }; + +} + +#endif --- botan/data_snk.cpp +++ botan/data_snk.cpp @@ -0,0 +1,51 @@ +/************************************************* +* DataSink Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Write to a stream * +*************************************************/ +void DataSink_Stream::write(const byte out[], u32bit length) + { + sink->write((const char*)out, length); + if(!sink->good()) + throw Stream_IO_Error("DataSink_Stream: Failure writing to " + fsname); + } + +/************************************************* +* DataSink_Stream Constructor * +*************************************************/ +DataSink_Stream::DataSink_Stream(std::ostream& stream) : fsname("std::ostream") + { + sink = &stream; + owns = false; + } + +/************************************************* +* DataSink_Stream Constructor * +*************************************************/ +DataSink_Stream::DataSink_Stream(const std::string& file) : fsname(file) + { + sink = new std::ofstream(fsname.c_str()); + if(!sink->good()) + throw Stream_IO_Error("DataSink_Stream: Failure opening " + fsname); + owns = true; + } + +/************************************************* +* DataSink_Stream Destructor * +*************************************************/ +DataSink_Stream::~DataSink_Stream() + { + if(owns) + delete sink; + sink = 0; + } + +} --- botan/data_snk.h +++ botan/data_snk.h @@ -0,0 +1,46 @@ +/************************************************* +* DataSink Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DATA_SINK_H__ +#define BOTAN_DATA_SINK_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Generic DataSink Interface * +*************************************************/ +class DataSink : public Filter + { + public: + bool attachable() { return false; } + DataSink() {} + virtual ~DataSink() {} + private: + DataSink& operator=(const DataSink&) { return (*this); } + DataSink(const DataSink&); + }; + +/************************************************* +* Stream-Based DataSink * +*************************************************/ +class DataSink_Stream : public DataSink + { + public: + void write(const byte[], u32bit); + DataSink_Stream(std::ostream&); + DataSink_Stream(const std::string&); + ~DataSink_Stream(); + private: + const std::string fsname; + std::ostream* sink; + bool owns; + }; + +} + +#endif --- botan/data_src.cpp +++ botan/data_src.cpp @@ -0,0 +1,168 @@ +/************************************************* +* DataSource Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Read a single byte from the DataSource * +*************************************************/ +u32bit DataSource::read_byte(byte& out) + { + return read(&out, 1); + } + +/************************************************* +* Peek a single byte from the DataSource * +*************************************************/ +u32bit DataSource::peek_byte(byte& out) const + { + return peek(&out, 1, 0); + } + +/************************************************* +* Discard the next N bytes of the data * +*************************************************/ +u32bit DataSource::discard_next(u32bit n) + { + u32bit discarded = 0; + byte dummy; + for(u32bit j = 0; j != n; j++) + discarded = read_byte(dummy); + return discarded; + } + +/************************************************* +* Read from a memory buffer * +*************************************************/ +u32bit DataSource_Memory::read(byte out[], u32bit length) + { + u32bit got = std::min(source.size() - offset, length); + copy_mem(out, source + offset, got); + offset += got; + return got; + } + +/************************************************* +* Peek into a memory buffer * +*************************************************/ +u32bit DataSource_Memory::peek(byte out[], u32bit length, + u32bit peek_offset) const + { + const u32bit bytes_left = source.size() - offset; + if(peek_offset >= bytes_left) return 0; + + u32bit 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 byte in[], u32bit length) + { + source.set(in, length); + offset = 0; + } + +/************************************************* +* DataSource_Memory Constructor * +*************************************************/ +DataSource_Memory::DataSource_Memory(const MemoryRegion& in) + { + source = in; + offset = 0; + } + +/************************************************* +* Read from a stream * +*************************************************/ +u32bit DataSource_Stream::read(byte out[], u32bit length) + { + source->read((char*)out, length); + if(source->bad()) + throw Stream_IO_Error("DataSource_Stream::read: Source failure"); + + u32bit got = source->gcount(); + total_read += got; + return (u32bit)got; + } + +/************************************************* +* Peek into a stream * +*************************************************/ +u32bit DataSource_Stream::peek(byte out[], u32bit length, u32bit offset) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); + + SecureVector buf(offset); + source->read((char*)buf.begin(), buf.size()); + if(source->bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + u32bit got = source->gcount(); + + if(got == offset) + { + source->read((char*)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 fsname; + } + +/************************************************* +* DataSource_Stream Constructor * +*************************************************/ +DataSource_Stream::DataSource_Stream(const std::string& file) : fsname(file) + { + source = new std::ifstream(fsname.c_str()); + if(!source->good()) + throw Stream_IO_Error("DataSource_Stream: Failure opening " + fsname); + total_read = 0; + } + +/************************************************* +* DataSource_Stream Destructor * +*************************************************/ +DataSource_Stream::~DataSource_Stream() + { + delete source; + } + +} --- botan/data_src.h +++ botan/data_src.h @@ -0,0 +1,74 @@ +/************************************************* +* DataSource Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DATA_SRC_H__ +#define BOTAN_DATA_SRC_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Generic DataSource Interface * +*************************************************/ +class DataSource + { + public: + virtual u32bit read(byte[], u32bit) = 0; + virtual u32bit peek(byte[], u32bit, u32bit) const = 0; + virtual bool end_of_data() const = 0; + virtual std::string id() const { return ""; } + + u32bit read_byte(byte&); + u32bit peek_byte(byte&) const; + u32bit discard_next(u32bit); + + DataSource() {} + virtual ~DataSource() {} + private: + DataSource& operator=(const DataSource&) { return (*this); } + DataSource(const DataSource&); + }; + +/************************************************* +* Memory-Based DataSource * +*************************************************/ +class DataSource_Memory : public DataSource + { + public: + u32bit read(byte[], u32bit); + u32bit peek(byte[], u32bit, u32bit) const; + bool end_of_data() const; + + DataSource_Memory(const byte[], u32bit); + DataSource_Memory(const MemoryRegion&); + private: + SecureVector source; + u32bit offset; + }; + +/************************************************* +* Stream-Based DataSource * +*************************************************/ +class DataSource_Stream : public DataSource + { + public: + u32bit read(byte[], u32bit); + u32bit peek(byte[], u32bit, u32bit) const; + bool end_of_data() const; + std::string id() const; + + DataSource_Stream(const std::string&); + ~DataSource_Stream(); + private: + const std::string fsname; + std::istream* source; + u32bit total_read; + }; + +} + +#endif --- botan/def_eng.cpp +++ botan/def_eng.cpp @@ -0,0 +1,155 @@ +/************************************************* +* Default Engine Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Simply return a mode object of choice * +*************************************************/ +Keyed_Filter* get_mode(Cipher_Dir direction, const std::string& cipher, + const std::string& mode, const std::string& pad = "", + u32bit bits = 0) + { + if(mode == "ECB") + { + if(direction == ENCRYPTION) return new ECB_Encryption(cipher, pad); + else return new ECB_Decryption(cipher, pad); + } + else if(mode == "CFB") + { + if(direction == ENCRYPTION) return new CFB_Encryption(cipher, bits); + else return new CFB_Decryption(cipher, bits); + } + else if(mode == "CBC") + { + if(pad == "CTS") + { + if(direction == ENCRYPTION) return new CTS_Encryption(cipher); + else return new CTS_Decryption(cipher); + } + if(direction == ENCRYPTION) return new CBC_Encryption(cipher, pad); + else return new CBC_Decryption(cipher, pad); + } + else if(mode == "EAX") + { + if(direction == ENCRYPTION) return new EAX_Encryption(cipher, bits); + else return new EAX_Decryption(cipher, bits); + } + else + throw Internal_Error("get_mode: " + cipher + "/" + mode + "/" + pad); + } + +} +/************************************************* +* Get a cipher object * +*************************************************/ +Keyed_Filter* Default_Engine::get_cipher(const std::string& algo_spec, + Cipher_Dir direction) + { + std::vector algo_parts = split_on(algo_spec, '/'); + if(algo_parts.size() == 0) + throw Invalid_Algorithm_Name(algo_spec); + + const std::string cipher = algo_parts[0]; + + if(have_stream_cipher(cipher)) + { + if(algo_parts.size() == 1) + return new StreamCipher_Filter(cipher); + return 0; + } + else if(have_block_cipher(cipher)) + { + if(algo_parts.size() != 2 && algo_parts.size() != 3) + return 0; + + std::string mode = algo_parts[1]; + u32bit bits = 0; + + if(mode.find("CFB") != std::string::npos || + mode.find("EAX") != std::string::npos) + { + std::vector algo_info = parse_algorithm_name(mode); + mode = algo_info[0]; + if(algo_info.size() == 1) + bits = 8*block_size_of(cipher); + else if(algo_info.size() == 2) + bits = to_u32bit(algo_info[1]); + else + throw Invalid_Algorithm_Name(algo_spec); + } + + std::string padding; + if(algo_parts.size() == 3) + padding = algo_parts[2]; + else + padding = (mode == "CBC") ? "PKCS7" : "NoPadding"; + + if(mode == "ECB" && padding == "CTS") + return 0; + else if((mode != "CBC" && mode != "ECB") && padding != "NoPadding") + throw Invalid_Algorithm_Name(algo_spec); + + if(mode == "OFB") return new OFB(cipher); + else if(mode == "CTR-BE") return new CTR_BE(cipher); + else if(mode == "ECB" || mode == "CBC" || mode == "CTS" || + mode == "CFB" || mode == "EAX") + return get_mode(direction, cipher, mode, padding, bits); + else + return 0; + } + + return 0; + } + +/************************************************* +* Look for an algorithm with this name * +*************************************************/ +BlockCipher* Default_Engine::find_block_cipher(const std::string& name) const + { + return Algolist::get_block_cipher(name); + } + +/************************************************* +* Look for an algorithm with this name * +*************************************************/ +StreamCipher* Default_Engine::find_stream_cipher(const std::string& name) const + { + return Algolist::get_stream_cipher(name); + } + +/************************************************* +* Look for an algorithm with this name * +*************************************************/ +HashFunction* Default_Engine::find_hash(const std::string& name) const + { + return Algolist::get_hash(name); + } + +/************************************************* +* Look for an algorithm with this name * +*************************************************/ +MessageAuthenticationCode* +Default_Engine::find_mac(const std::string& name) const + { + return Algolist::get_mac(name); + } + +} --- botan/def_eng.h +++ botan/def_eng.h @@ -0,0 +1,40 @@ +/************************************************* +* Default Engine Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DEFAULT_ENGINE_H__ +#define BOTAN_DEFAULT_ENGINE_H__ + +#include + +namespace Botan { + +/************************************************* +* Default Engine * +*************************************************/ +class Default_Engine : public Engine + { + public: + IF_Operation* if_op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&) const; + DSA_Operation* dsa_op(const DL_Group&, const BigInt&, + const BigInt&) const; + NR_Operation* nr_op(const DL_Group&, const BigInt&, const BigInt&) const; + ELG_Operation* elg_op(const DL_Group&, const BigInt&, + const BigInt&) const; + DH_Operation* dh_op(const DL_Group&, const BigInt&) const; + ModularReducer* reducer(const BigInt&, bool) const; + + Keyed_Filter* get_cipher(const std::string&, Cipher_Dir); + private: + BlockCipher* find_block_cipher(const std::string&) const; + StreamCipher* find_stream_cipher(const std::string&) const; + HashFunction* find_hash(const std::string&) const; + MessageAuthenticationCode* find_mac(const std::string&) const; + }; + +} + +#endif --- botan/def_ops.cpp +++ botan/def_ops.cpp @@ -0,0 +1,352 @@ +/************************************************* +* Default Engine PK Operations Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Default IF Operation * +*************************************************/ +class Default_IF_Op : public IF_Operation + { + public: + BigInt public_op(const BigInt& i) const { return powermod_e_n(i); } + BigInt private_op(const BigInt&) const; + + IF_Operation* clone() const { return new Default_IF_Op(*this); } + + Default_IF_Op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&); + private: + const BigInt q, c; + FixedExponent_Exp powermod_e_n, powermod_d1_p, powermod_d2_q; + }; + +/************************************************* +* Default_IF_Op Constructor * +*************************************************/ +Default_IF_Op::Default_IF_Op(const BigInt& e, const BigInt& n, const BigInt&, + const BigInt& p, const BigInt& qx, + const BigInt& d1, const BigInt& d2, + const BigInt& cx) : q(qx), c(cx) + { + powermod_e_n = FixedExponent_Exp(e, n); + if(d1 != 0 && d2 != 0 && p != 0 && q != 0) + { + powermod_d1_p = FixedExponent_Exp(d1, p); + powermod_d2_q = FixedExponent_Exp(d2, q); + } + } + +/************************************************* +* Default IF Private Operation * +*************************************************/ +BigInt Default_IF_Op::private_op(const BigInt& i) const + { + if(q == 0) + throw Internal_Error("Default_IF_Op::private_op: No private key"); + + BigInt j1 = powermod_d1_p(i); + BigInt j2 = powermod_d2_q(i); + return mul_add(powermod_d1_p.reduce(sub_mul(j1, j2, c)), q, j2); + } + +/************************************************* +* Default DSA Operation * +*************************************************/ +class Default_DSA_Op : public DSA_Operation + { + public: + bool verify(const byte[], u32bit, const byte[], u32bit) const; + SecureVector sign(const byte[], u32bit, const BigInt&) const; + + DSA_Operation* clone() const { return new Default_DSA_Op(*this); } + + Default_DSA_Op(const DL_Group&, const BigInt&, const BigInt&); + private: + const BigInt x, y; + const DL_Group group; + FixedBase_Exp powermod_g_p, powermod_y_p; + }; + +/************************************************* +* Default_DSA_Op Constructor * +*************************************************/ +Default_DSA_Op::Default_DSA_Op(const DL_Group& grp, const BigInt& y1, + const BigInt& x1) : x(x1), y(y1), group(grp) + { + powermod_g_p = FixedBase_Exp(group.get_g(), group.get_p()); + powermod_y_p = FixedBase_Exp(y, group.get_p()); + } + +/************************************************* +* Default DSA Verify Operation * +*************************************************/ +bool Default_DSA_Op::verify(const byte msg[], u32bit msg_len, + const byte sig[], u32bit sig_len) const + { + const BigInt& q = group.get_q(); + const BigInt& p = group.get_p(); + + 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); + s = mul_mod(powermod_g_p(mul_mod(s, i, q)), + powermod_y_p(mul_mod(s, r, q)), p); + + return (s % q == r); + } + +/************************************************* +* Default DSA Sign Operation * +*************************************************/ +SecureVector Default_DSA_Op::sign(const byte in[], u32bit length, + const BigInt& k) const + { + if(x == 0) + throw Internal_Error("Default_DSA_Op::sign: No private key"); + + const BigInt& q = group.get_q(); + BigInt i(in, length); + + BigInt r = powermod_g_p(k) % q; + BigInt s = mul_mod(inverse_mod(k, q), mul_add(x, r, i), q); + if(r.is_zero() || s.is_zero()) + throw Internal_Error("Default_DSA_Op::sign: r or s was zero"); + + SecureVector output(2*q.bytes()); + r.binary_encode(output + (output.size() / 2 - r.bytes())); + s.binary_encode(output + (output.size() - s.bytes())); + return output; + } + +/************************************************* +* Default NR Operation * +*************************************************/ +class Default_NR_Op : public NR_Operation + { + public: + SecureVector verify(const byte[], u32bit) const; + SecureVector sign(const byte[], u32bit, const BigInt&) const; + + NR_Operation* clone() const { return new Default_NR_Op(*this); } + + Default_NR_Op(const DL_Group&, const BigInt&, const BigInt&); + private: + const BigInt x, y; + const DL_Group group; + FixedBase_Exp powermod_g_p, powermod_y_p; + }; + +/************************************************* +* Default_NR_Op Constructor * +*************************************************/ +Default_NR_Op::Default_NR_Op(const DL_Group& grp, const BigInt& y1, + const BigInt& x1) : x(x1), y(y1), group(grp) + { + powermod_g_p = FixedBase_Exp(group.get_g(), group.get_p()); + powermod_y_p = FixedBase_Exp(y, group.get_p()); + } + +/************************************************* +* Default NR Verify Operation * +*************************************************/ +SecureVector Default_NR_Op::verify(const byte in[], u32bit length) const + { + const BigInt& p = group.get_p(); + const BigInt& q = group.get_q(); + + if(length != 2*q.bytes()) + return false; + + BigInt c(in, q.bytes()); + BigInt d(in + q.bytes(), q.bytes()); + + if(c.is_zero() || c >= q || d >= q) + throw Invalid_Argument("Default_NR_Op::verify: Invalid signature"); + + BigInt i = mul_mod(powermod_g_p(d), powermod_y_p(c), p); + return BigInt::encode((c - i) % q); + } + +/************************************************* +* Default NR Sign Operation * +*************************************************/ +SecureVector Default_NR_Op::sign(const byte in[], u32bit length, + const BigInt& k) const + { + if(x == 0) + throw Internal_Error("Default_NR_Op::sign: No private key"); + + const BigInt& q = group.get_q(); + + BigInt f(in, length); + + if(f >= q) + throw Invalid_Argument("Default_NR_Op::sign: Input is out of range"); + + BigInt c = (powermod_g_p(k) + f) % q; + if(c.is_zero()) + throw Internal_Error("Default_NR_Op::sign: c was zero"); + BigInt d = (k - x * c) % q; + + SecureVector output(2*q.bytes()); + c.binary_encode(output + (output.size() / 2 - c.bytes())); + d.binary_encode(output + (output.size() - d.bytes())); + return output; + } + +/************************************************* +* Default ElGamal Operation * +*************************************************/ +class Default_ELG_Op : public ELG_Operation + { + public: + SecureVector encrypt(const byte[], u32bit, const BigInt&) const; + BigInt decrypt(const BigInt&, const BigInt&) const; + + ELG_Operation* clone() const { return new Default_ELG_Op(*this); } + + Default_ELG_Op(const DL_Group&, const BigInt&, const BigInt&); + private: + const BigInt p; + FixedBase_Exp powermod_g_p, powermod_y_p; + FixedExponent_Exp powermod_x_p; + }; + +/************************************************* +* Default_ELG_Op Constructor * +*************************************************/ +Default_ELG_Op::Default_ELG_Op(const DL_Group& group, const BigInt& y, + const BigInt& x) : p(group.get_p()) + { + powermod_g_p = FixedBase_Exp(group.get_g(), p); + powermod_y_p = FixedBase_Exp(y, p); + + if(x != 0) + powermod_x_p = FixedExponent_Exp(x, p); + } + +/************************************************* +* Default ElGamal Encrypt Operation * +*************************************************/ +SecureVector Default_ELG_Op::encrypt(const byte in[], u32bit length, + const BigInt& k) const + { + BigInt m(in, length); + if(m >= p) + throw Invalid_Argument("Default_ELG_Op::encrypt: Input is too large"); + + BigInt a = powermod_g_p(k); + BigInt b = mul_mod(m, powermod_y_p(k), p); + + SecureVector 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; + } + +/************************************************* +* Default ElGamal Decrypt Operation * +*************************************************/ +BigInt Default_ELG_Op::decrypt(const BigInt& a, const BigInt& b) const + { + if(!powermod_x_p.initialized()) + throw Internal_Error("Default_ELG_Op::decrypt: No private key"); + + if(a >= p || b >= p) + throw Invalid_Argument("Default_ELG_Op: Invalid message"); + + return mul_mod(b, inverse_mod(powermod_x_p(a), p), p); + } + +/************************************************* +* Default DH Operation * +*************************************************/ +class Default_DH_Op : public DH_Operation + { + public: + BigInt agree(const BigInt& i) const { return powermod_x_p(i); } + DH_Operation* clone() const { return new Default_DH_Op(*this); } + + Default_DH_Op(const DL_Group& group, const BigInt& x) : + powermod_x_p(x, group.get_p()) {} + private: + const FixedExponent_Exp powermod_x_p; + }; + +} + +/************************************************* +* Acquire an IF op * +*************************************************/ +IF_Operation* Default_Engine::if_op(const BigInt& e, const BigInt& n, + const BigInt& d, const BigInt& p, + const BigInt& q, const BigInt& d1, + const BigInt& d2, const BigInt& c) const + { + return new Default_IF_Op(e, n, d, p, q, d1, d2, c); + } + +/************************************************* +* Acquire a DSA op * +*************************************************/ +DSA_Operation* Default_Engine::dsa_op(const DL_Group& group, const BigInt& y, + const BigInt& x) const + { + return new Default_DSA_Op(group, y, x); + } + +/************************************************* +* Acquire a NR op * +*************************************************/ +NR_Operation* Default_Engine::nr_op(const DL_Group& group, const BigInt& y, + const BigInt& x) const + { + return new Default_NR_Op(group, y, x); + } + +/************************************************* +* Acquire an ElGamal op * +*************************************************/ +ELG_Operation* Default_Engine::elg_op(const DL_Group& group, const BigInt& y, + const BigInt& x) const + { + return new Default_ELG_Op(group, y, x); + } + +/************************************************* +* Acquire a DH op * +*************************************************/ +DH_Operation* Default_Engine::dh_op(const DL_Group& group, + const BigInt& x) const + { + return new Default_DH_Op(group, x); + } + +/************************************************* +* Acquire a ModularReducer * +*************************************************/ +ModularReducer* Default_Engine::reducer(const BigInt& n, bool) const + { + return new BarrettReducer(n); + } + +} --- botan/defalloc.cpp +++ botan/defalloc.cpp @@ -0,0 +1,81 @@ +/************************************************* +* Basic Allocators Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Perform Memory Allocation * +*************************************************/ +void* do_malloc(u32bit n, bool do_lock) + { + void* ptr = std::malloc(n); + + if(!ptr) + return 0; + + if(do_lock) + lock_mem(ptr, n); + + std::memset(ptr, 0, n); + return ptr; + } + +/************************************************* +* Perform Memory Deallocation * +*************************************************/ +void do_free(void* ptr, u32bit n, bool do_lock) + { + if(!ptr) + return; + + std::memset(ptr, 0, n); + if(do_lock) + unlock_mem(ptr, n); + + std::free(ptr); + } + +} + +/************************************************* +* Malloc_Allocator's Allocation * +*************************************************/ +void* Malloc_Allocator::alloc_block(u32bit n) const + { + return do_malloc(n, false); + } + +/************************************************* +* Malloc_Allocator's Deallocation * +*************************************************/ +void Malloc_Allocator::dealloc_block(void* ptr, u32bit n) const + { + do_free(ptr, n, false); + } + +/************************************************* +* Locking_Allocator's Allocation * +*************************************************/ +void* Locking_Allocator::alloc_block(u32bit n) const + { + return do_malloc(n, true); + } + +/************************************************* +* Locking_Allocator's Deallocation * +*************************************************/ +void Locking_Allocator::dealloc_block(void* ptr, u32bit n) const + { + do_free(ptr, n, true); + } + +} --- botan/defalloc.h +++ botan/defalloc.h @@ -0,0 +1,37 @@ +/************************************************* +* Basic Allocators Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_BASIC_ALLOC_H__ +#define BOTAN_BASIC_ALLOC_H__ + +#include + +namespace Botan { + +/************************************************* +* Malloc Allocator * +*************************************************/ +class Malloc_Allocator : public Pooling_Allocator + { + private: + void* alloc_block(u32bit) const; + void dealloc_block(void*, u32bit) const; + }; + +/************************************************* +* Locking Allocator * +*************************************************/ +class Locking_Allocator : public Pooling_Allocator + { + private: + void* alloc_block(u32bit) const; + void dealloc_block(void*, u32bit) const; + u32bit prealloc_bytes() const { return 128*1024; } + bool should_not_free() const { return true; } + }; + +} + +#endif --- botan/der_code.cpp +++ botan/der_code.cpp @@ -0,0 +1,174 @@ +/************************************************* +* DER Coding Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +namespace DER { + +/************************************************* +* Put some arbitrary bytes into a SEQUENCE * +*************************************************/ +SecureVector put_in_sequence(const MemoryRegion& contents) + { + DER_Encoder encoder; + encoder.start_sequence(); + encoder.add_raw_octets(contents); + encoder.end_sequence(); + return encoder.get_contents(); + } + +/************************************************* +* DER encode NULL * +*************************************************/ +void encode_null(DER_Encoder& encoder) + { + encoder.add_object(NULL_TAG, UNIVERSAL, 0, 0); + } + +/************************************************* +* DER encode a BOOLEAN * +*************************************************/ +void encode(DER_Encoder& encoder, bool is_true) + { + encode(encoder, is_true, BOOLEAN, UNIVERSAL); + } + +/************************************************* +* DER encode a small INTEGER * +*************************************************/ +void encode(DER_Encoder& encoder, u32bit n) + { + encode(encoder, BigInt(n), INTEGER, UNIVERSAL); + } + +/************************************************* +* DER encode a small INTEGER * +*************************************************/ +void encode(DER_Encoder& encoder, int n) + { + if(n < 0) + throw Invalid_Argument("DER::encode(int): n must be >= 0"); + encode(encoder, BigInt(n), INTEGER, UNIVERSAL); + } + +/************************************************* +* DER encode an INTEGER * +*************************************************/ +void encode(DER_Encoder& encoder, const BigInt& n) + { + encode(encoder, n, INTEGER, UNIVERSAL); + } + +/************************************************* +* DER encode an OCTET STRING or BIT STRING * +*************************************************/ +void encode(DER_Encoder& encoder, const MemoryRegion& octets, + ASN1_Tag real_type) + { + encode(encoder, octets.begin(), octets.size(), + real_type, real_type, UNIVERSAL); + } + +/************************************************* +* DER encode an OCTET STRING or BIT STRING * +*************************************************/ +void encode(DER_Encoder& encoder, const byte octets[], u32bit length, + ASN1_Tag real_type) + { + encode(encoder, octets, length, real_type, real_type, UNIVERSAL); + } + +/************************************************* +* DER encode a BOOLEAN * +*************************************************/ +void encode(DER_Encoder& encoder, bool is_true, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(is_true) + encoder.add_object(type_tag, class_tag, 0xFF); + else + encoder.add_object(type_tag, class_tag, 0x00); + } + +/************************************************* +* DER encode a small INTEGER * +*************************************************/ +void encode(DER_Encoder& encoder, u32bit n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + encode(encoder, BigInt(n), type_tag, class_tag); + } + +/************************************************* +* DER encode a small INTEGER * +*************************************************/ +void encode(DER_Encoder& encoder, int n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n < 0) + throw Invalid_Argument("DER::encode(int): n must be >= 0"); + encode(encoder, BigInt(n), type_tag, class_tag); + } + +/************************************************* +* DER encode an INTEGER * +*************************************************/ +void encode(DER_Encoder& encoder, const BigInt& n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n == 0) + encoder.add_object(type_tag, class_tag, 0); + else + { + bool extra_zero = (n.bits() % 8 == 0); + SecureVector contents(extra_zero + n.bytes()); + BigInt::encode(contents.begin() + extra_zero, n); + if(n < 0) + { + for(u32bit j = 0; j != contents.size(); j++) + contents[j] = ~contents[j]; + for(u32bit j = contents.size(); j > 0; j--) + if(++contents[j-1]) + break; + } + encoder.add_object(type_tag, class_tag, contents); + } + } + +/************************************************* +* DER encode an OCTET STRING or BIT STRING * +*************************************************/ +void encode(DER_Encoder& encoder, const MemoryRegion& octets, + ASN1_Tag real_type, ASN1_Tag type_tag, ASN1_Tag class_tag) + { + encode(encoder, octets.begin(), octets.size(), + real_type, type_tag, class_tag); + } + +/************************************************* +* DER encode an OCTET STRING or BIT STRING * +*************************************************/ +void encode(DER_Encoder& encoder, const byte octets[], u32bit 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 == OCTET_STRING) + encoder.add_object(type_tag, class_tag, octets, length); + else + { + SecureVector encoded; + encoded.append(0); + encoded.append(octets, length); + encoder.add_object(type_tag, class_tag, encoded); + } + } + +} + +} --- botan/der_enc.cpp +++ botan/der_enc.cpp @@ -0,0 +1,336 @@ +/************************************************* +* DER Encoder Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* DER encode an ASN.1 type tag * +*************************************************/ +SecureVector encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if((class_tag | 0xE0) != 0xE0) + throw Encoding_Error("DER_Encoder: Invalid class tag " + + to_string(class_tag)); + + SecureVector encoded_tag; + if(type_tag <= 30) + encoded_tag.append((byte)(type_tag | class_tag)); + else + { + u32bit blocks = high_bit(type_tag) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + encoded_tag.append(class_tag | 0x1F); + for(u32bit k = 0; k != blocks - 1; k++) + encoded_tag.append(0x80 | ((type_tag >> 7*(blocks-k-1)) & 0x7F)); + encoded_tag.append(type_tag & 0x7F); + } + + return encoded_tag; + } + +/************************************************* +* DER encode an ASN.1 length field * +*************************************************/ +SecureVector encode_length(u32bit length) + { + SecureVector encoded_length; + if(length <= 127) + encoded_length.append((byte)length); + else + { + const u32bit top_byte = significant_bytes(length); + encoded_length.append((byte)(0x80 | top_byte)); + for(u32bit j = 4-top_byte; j != 4; j++) + encoded_length.append(get_byte(j, length)); + } + return encoded_length; + } + +/************************************************* +* A comparison functor for sorting SET objects * +*************************************************/ +class DER_Cmp + { + public: + bool operator()(const MemoryRegion&, + const MemoryRegion&) const; + }; + +/************************************************* +* Compare two encodings, as specified by X.690 * +*************************************************/ +bool DER_Cmp::operator()(const MemoryRegion& a, + const MemoryRegion& b) const + { + if(a.size() < b.size()) return true; + if(a.size() > b.size()) return false; + + for(u32bit j = 0; j != a.size(); j++) + { + if(a[j] < b[j]) return true; + if(a[j] > b[j]) return false; + } + return false; + } + +} + +/************************************************* +* Return the encoded SEQUENCE/SET * +*************************************************/ +SecureVector DER_Encoder::DER_Sequence::get_contents() + { + const ASN1_Tag real_class_tag = ASN1_Tag(class_tag | CONSTRUCTED); + + SecureVector encoded_tag = encode_tag(type_tag, real_class_tag); + + if(is_a_set) + { + std::sort(set_contents.begin(), set_contents.end(), DER_Cmp()); + for(u32bit j = 0; j != set_contents.size(); j++) + contents.append(set_contents[j]); + set_contents.clear(); + } + + SecureVector encoded_length = encode_length(contents.size()); + + SecureVector retval; + retval.append(encoded_tag); + retval.append(encoded_length); + retval.append(contents); + contents.destroy(); + return retval; + } + +/************************************************* +* Add an encoded value to the SEQUENCE/SET * +*************************************************/ +void DER_Encoder::DER_Sequence::add_bytes(const byte data[], u32bit length) + { + if(is_a_set) + { + set_contents.push_back(SecureVector(data, length)); + } + else + contents.append(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, bool b) : + type_tag(t1), class_tag(t2), is_a_set(b) + { + } + +/************************************************* +* Return the encoded contents * +*************************************************/ +SecureVector DER_Encoder::get_contents() + { + if(sequence_level != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + SecureVector retval; + retval = contents; + contents.destroy(); + return retval; + } + +/************************************************* +* Start a new ASN.1 SEQUENCE/SET/EXPLICIT * +*************************************************/ +void DER_Encoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag, + bool is_a_set) + { + sequence_level++; + subsequences.push_back(DER_Sequence(type_tag, class_tag, is_a_set)); + } + +/************************************************* +* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT * +*************************************************/ +void DER_Encoder::end_cons(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(sequence_level == 0) + throw Invalid_State("DER_Encoder::end_cons: No such sequence"); + sequence_level--; + if(subsequences[sequence_level].tag_of() != ASN1_Tag(type_tag | class_tag)) + throw Invalid_Argument("DER_Encoder::end_cons: Tag mismatch"); + + SecureVector seq = subsequences[sequence_level].get_contents(); + subsequences.pop_back(); + add_raw_octets(seq); + } + +/************************************************* +* Start a new ASN.1 SEQUENCE * +*************************************************/ +void DER_Encoder::start_sequence(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + start_cons(type_tag, class_tag, false); + } + +/************************************************* +* Finish the current ASN.1 SEQUENCE * +*************************************************/ +void DER_Encoder::end_sequence(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + end_cons(type_tag, class_tag); + } + +/************************************************* +* Start a new ASN.1 SET * +*************************************************/ +void DER_Encoder::start_set(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + start_cons(type_tag, class_tag, true); + } + +/************************************************* +* Finish the current ASN.1 SET * +*************************************************/ +void DER_Encoder::end_set(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + end_cons(type_tag, class_tag); + } + +/************************************************* +* Start a new ASN.1 SEQUENCE * +*************************************************/ +void DER_Encoder::start_sequence() + { + start_sequence(SEQUENCE, UNIVERSAL); + } + +/************************************************* +* Finish the current ASN.1 SEQUENCE * +*************************************************/ +void DER_Encoder::end_sequence() + { + end_sequence(SEQUENCE, UNIVERSAL); + } + +/************************************************* +* Start a new ASN.1 SET * +*************************************************/ +void DER_Encoder::start_set() + { + start_set(SET, UNIVERSAL); + } + +/************************************************* +* Finish the current ASN.1 SET * +*************************************************/ +void DER_Encoder::end_set() + { + end_set(SET, UNIVERSAL); + } + +/************************************************* +* Start a new ASN.1 EXPLICIT encoding * +*************************************************/ +void DER_Encoder::start_explicit(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + start_cons(type_tag, class_tag, false); + } + +/************************************************* +* Finish the current ASN.1 EXPLICIT encoding * +*************************************************/ +void DER_Encoder::end_explicit(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + end_cons(type_tag, class_tag); + } + +/************************************************* +* Write raw octets into the stream * +*************************************************/ +void DER_Encoder::add_raw_octets(const MemoryRegion& octets) + { + add_raw_octets(octets.begin(), octets.size()); + } + +/************************************************* +* Write raw octets into the stream * +*************************************************/ +void DER_Encoder::add_raw_octets(const byte octets[], u32bit length) + { + if(sequence_level == 0) + contents.append(octets, length); + else + subsequences[sequence_level-1].add_bytes(octets, length); + } + +/************************************************* +* Write the encoding of the octet(s) * +*************************************************/ +void DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const byte rep[], u32bit length) + { + SecureVector encoded_tag = encode_tag(type_tag, class_tag); + SecureVector encoded_length = encode_length(length); + + SecureVector buffer; + buffer.append(encoded_tag); + buffer.append(encoded_length); + buffer.append(rep, length); + + add_raw_octets(buffer); + } + +/************************************************* +* Write the encoding of the octet(s) * +*************************************************/ +void DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const MemoryRegion& rep_buf) + { + const byte* rep = rep_buf.begin(); + const u32bit rep_len = rep_buf.size(); + add_object(type_tag, class_tag, rep, rep_len); + } + +/************************************************* +* Write the encoding of the octet(s) * +*************************************************/ +void DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& rep_str) + { + const byte* rep = (const byte*)rep_str.c_str(); + const u32bit rep_len = rep_str.size(); + add_object(type_tag, class_tag, rep, rep_len); + } + +/************************************************* +* Write the encoding of the octet * +*************************************************/ +void DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, byte rep) + { + add_object(type_tag, class_tag, &rep, 1); + } + +/************************************************* +* DER_Encoder Constructor * +*************************************************/ +DER_Encoder::DER_Encoder() + { + sequence_level = 0; + } + +} --- botan/der_enc.h +++ botan/der_enc.h @@ -0,0 +1,96 @@ +/************************************************* +* DER Encoder Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DER_ENCODER_H__ +#define BOTAN_DER_ENCODER_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* General DER Encoding Object * +*************************************************/ +class DER_Encoder + { + public: + SecureVector get_contents(); + + void start_sequence(ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + void end_sequence(ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + void start_set(ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + void end_set(ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + + void start_sequence(); + void end_sequence(); + void start_set(); + void end_set(); + + void start_explicit(ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + void end_explicit(ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + + void add_raw_octets(const byte[], u32bit); + void add_raw_octets(const MemoryRegion&); + + void add_object(ASN1_Tag, ASN1_Tag, const byte[], u32bit); + void add_object(ASN1_Tag, ASN1_Tag, const MemoryRegion&); + void add_object(ASN1_Tag, ASN1_Tag, const std::string&); + void add_object(ASN1_Tag, ASN1_Tag, byte); + + DER_Encoder(); + private: + void start_cons(ASN1_Tag, ASN1_Tag, bool); + void end_cons(ASN1_Tag, ASN1_Tag); + class DER_Sequence + { + public: + ASN1_Tag tag_of() const; + SecureVector get_contents(); + void add_bytes(const byte[], u32bit); + DER_Sequence(ASN1_Tag, ASN1_Tag, bool = false); + private: + ASN1_Tag type_tag, class_tag; + bool is_a_set; + SecureVector contents; + std::vector< SecureVector > set_contents; + }; + SecureVector contents; + std::vector subsequences; + u32bit sequence_level; + }; + +/************************************************* +* DER Encoding Functions * +*************************************************/ +namespace DER { + +void encode_null(DER_Encoder&); +void encode(DER_Encoder&, const OID&); + +void encode(DER_Encoder&, bool); +void encode(DER_Encoder&, int); +void encode(DER_Encoder&, u32bit); +void encode(DER_Encoder&, const BigInt&); +void encode(DER_Encoder&, const MemoryRegion&, ASN1_Tag); +void encode(DER_Encoder&, const byte[], u32bit, ASN1_Tag); + +void encode(DER_Encoder&, bool, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void encode(DER_Encoder&, u32bit, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void encode(DER_Encoder&, const BigInt&, ASN1_Tag, + ASN1_Tag = CONTEXT_SPECIFIC); +void encode(DER_Encoder&, const MemoryRegion&, + ASN1_Tag, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); +void encode(DER_Encoder&, const byte[], u32bit, + ASN1_Tag, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + +SecureVector put_in_sequence(const MemoryRegion&); + +} + +} + +#endif --- botan/dh.cpp +++ botan/dh.cpp @@ -0,0 +1,111 @@ +/************************************************* +* Diffie-Hellman Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* DH_PublicKey Constructor * +*************************************************/ +DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + X509_load_hook(); + } + +/************************************************* +* Algorithm Specific X.509 Initialization Code * +*************************************************/ +void DH_PublicKey::X509_load_hook() + { + check_loaded_public(); + } + +/************************************************* +* Return the public value for key agreement * +*************************************************/ +MemoryVector DH_PublicKey::public_value() const + { + return BigInt::encode_1363(y, group_p().bytes()); + } + +/************************************************* +* Create a DH private key * +*************************************************/ +DH_PrivateKey::DH_PrivateKey(const DL_Group& grp) + { + group = grp; + + const BigInt& p = group_p(); + x = random_integer(2 * dl_work_factor(p.bits()), LongTermKey); + + PKCS8_load_hook(); + check_generated_private(); + } + +/************************************************* +* DH_PrivateKey Constructor * +*************************************************/ +DH_PrivateKey::DH_PrivateKey(const DL_Group& grp, const BigInt& x1, + const BigInt& y1) + { + group = grp; + y = y1; + x = x1; + + PKCS8_load_hook(); + check_loaded_private(); + } + +/************************************************* +* Algorithm Specific PKCS #8 Initialization Code * +*************************************************/ +void DH_PrivateKey::PKCS8_load_hook() + { + if(y == 0) + y = power_mod(group_g(), x, group_p()); + core = DH_Core(group, x); + } + +/************************************************* +* Return the public value for key agreement * +*************************************************/ +MemoryVector DH_PrivateKey::public_value() const + { + return DH_PublicKey::public_value(); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector DH_PrivateKey::derive_key(const byte w[], + u32bit w_len) const + { + return derive_key(BigInt::decode(w, w_len)); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector DH_PrivateKey::derive_key(const DH_PublicKey& key) const + { + return derive_key(key.get_y()); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector DH_PrivateKey::derive_key(const BigInt& w) const + { + const BigInt& p = group_p(); + if(w <= 1 || w >= p-1) + throw Invalid_Argument(algo_name() + "::derive_key: Invalid key input"); + return BigInt::encode_1363(core.agree(w), p.bytes()); + } + +} --- botan/dh.h +++ botan/dh.h @@ -0,0 +1,57 @@ +/************************************************* +* Diffie-Hellman Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DIFFIE_HELLMAN_H__ +#define BOTAN_DIFFIE_HELLMAN_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Diffie-Hellman Public Key * +*************************************************/ +class DH_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + MemoryVector public_value() const; + DH_PublicKey(const DL_Group&, const BigInt&); + protected: + std::string algo_name() const { return "DH"; } + DH_PublicKey() {} + private: + friend X509_PublicKey* get_public_key(const std::string&); + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + void X509_load_hook(); + }; + +/************************************************* +* Diffie-Hellman Private Key * +*************************************************/ +class DH_PrivateKey : public DH_PublicKey, + public PK_Key_Agreement_Key, + public virtual DL_Scheme_PrivateKey + { + public: + SecureVector derive_key(const byte[], u32bit) const; + SecureVector derive_key(const DH_PublicKey&) const; + SecureVector derive_key(const BigInt&) const; + + MemoryVector public_value() const; + + DH_PrivateKey(const DL_Group&); + DH_PrivateKey(const DL_Group&, const BigInt&, const BigInt& = 0); + private: + friend PKCS8_PrivateKey* get_private_key(const std::string&); + void PKCS8_load_hook(); + DH_PrivateKey() {} + + DH_Core core; + }; + +} + +#endif --- botan/divide.cpp +++ botan/divide.cpp @@ -0,0 +1,100 @@ +/************************************************* +* Division Algorithm Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Solve x = q * y + r * +*************************************************/ +void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r) + { + BigInt y = y_arg; + r = x; + + r.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + + modifying_divide(r, y, q); + + if(x.sign() == BigInt::Negative) + { + q.flip_sign(); + if(r.is_nonzero()) { --q; r = y_arg.abs() - r; } + } + if(y_arg.sign() == BigInt::Negative) + q.flip_sign(); + } + +/************************************************* +* Solve x = q * y + r * +*************************************************/ +void positive_divide(const BigInt& x, const BigInt& y_arg, + BigInt& q, BigInt& r) + { + BigInt y = y_arg; + r = x; + modifying_divide(r, y, q); + } + +/************************************************* +* Solve x = q * y + r * +*************************************************/ +void modifying_divide(BigInt& x, BigInt& y, BigInt& q) + { + if(y.is_zero()) + throw BigInt::DivideByZero(); + if(x.is_negative() || y.is_negative()) + throw Invalid_Argument("Arguments to modifying_divide must be positive"); + + s32bit compare = x.cmp(y); + if(compare == -1) { q = 0; return; } + if(compare == 0) { q = 1; x = 0; return; } + + u32bit shifts = 0; + while(y[y.sig_words()-1] < MP_WORD_TOP_BIT) + { x <<= 1; y <<= 1; shifts++; } + + u32bit n = x.sig_words() - 1, t = y.sig_words() - 1; + q.reg.create(n - t + 1); + if(n <= t) + { + while(x > y) { x -= y; q.add(1); } + x >>= shifts; + return; + } + + BigInt temp = y << (MP_WORD_BITS * (n-t)); + + while(x >= temp) { x -= temp; q[n-t]++; } + + for(u32bit j = n; j != t; j--) + { + const word x_j0 = x.word_at(j); + const word x_j1 = x.word_at(j-1); + const word y_t = y.word_at(t); + + if(x_j0 == y_t) + q[j-t-1] = MP_WORD_MAX; + else + q[j-t-1] = bigint_divop(x_j0, x_j1, y_t); + + while(bigint_divcore(q[j-t-1], y_t, y.word_at(t-1), + x_j0, x_j1, x.word_at(j-2))) + q[j-t-1]--; + + x -= (q[j-t-1] * y) << (MP_WORD_BITS * (j-t-1)); + if(x.is_negative()) + { + x += y << (MP_WORD_BITS * (j-t-1)); + q[j-t-1]--; + } + } + x >>= shifts; + } + +} --- botan/dl_algo.cpp +++ botan/dl_algo.cpp @@ -0,0 +1,105 @@ +/************************************************* +* DL Scheme Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Return the X.509 public key encoding * +*************************************************/ +MemoryVector DL_Scheme_PublicKey::DER_encode_pub() const + { + DER_Encoder encoder; + DER::encode(encoder, y); + return encoder.get_contents(); + } + +/************************************************* +* Return the X.509 parameters encoding * +*************************************************/ +MemoryVector DL_Scheme_PublicKey::DER_encode_params() const + { + return group.DER_encode(group_format()); + } + +/************************************************* +* Decode X.509 public key encoding * +*************************************************/ +void DL_Scheme_PublicKey::BER_decode_pub(DataSource& source) + { + BER_Decoder decoder(source); + BER::decode(decoder, y); + if(y < 2 || y >= group_p()) + throw Invalid_Argument(algo_name() + ": Invalid public key"); + X509_load_hook(); + } + +/************************************************* +* Decode X.509 algorithm parameters * +*************************************************/ +void DL_Scheme_PublicKey::BER_decode_params(DataSource& source) + { + group.BER_decode(source, group_format()); + } + +/************************************************* +* Return the PKCS #8 private key encoding * +*************************************************/ +SecureVector DL_Scheme_PrivateKey::DER_encode_priv() const + { + DER_Encoder encoder; + DER::encode(encoder, x); + return encoder.get_contents(); + } + +/************************************************* +* Decode a PKCS #8 private key encoding * +*************************************************/ +void DL_Scheme_PrivateKey::BER_decode_priv(DataSource& source) + { + BER_Decoder decoder(source); + BER::decode(decoder, x); + PKCS8_load_hook(); + check_loaded_private(); + } + +/************************************************* +* Check Public DL Parameters * +*************************************************/ +bool DL_Scheme_PublicKey::check_key(bool strong) const + { + if(y < 2 || y >= group_p()) + return false; + if(!group.verify_group(strong)) + return false; + return true; + } + +/************************************************* +* Check DL Scheme Private Parameters * +*************************************************/ +bool DL_Scheme_PrivateKey::check_key(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(strong)) + return false; + + if(!strong) + return true; + + if(y != power_mod(g, x, p)) + return false; + + return true; + } + +} --- botan/dl_algo.h +++ botan/dl_algo.h @@ -0,0 +1,67 @@ +/************************************************* +* DL Scheme Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DL_ALGO_H__ +#define BOTAN_DL_ALGO_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* DL Public Key * +*************************************************/ +class DL_Scheme_PublicKey : public virtual X509_PublicKey + { + public: + bool check_key(bool) const; + + const DL_Group& get_domain() const { return group; } + const BigInt& get_y() const { return y; } + + virtual ~DL_Scheme_PublicKey() {} + protected: + const BigInt& group_p() const { return group.get_p(); } + const BigInt& group_q() const { return group.get_q(); } + const BigInt& group_g() const { return group.get_g(); } + + BigInt y; + DL_Group group; + private: + MemoryVector DER_encode_pub() const; + MemoryVector DER_encode_params() const; + void BER_decode_pub(DataSource&); + void BER_decode_params(DataSource&); + + virtual DL_Group::Format group_format() const = 0; + virtual void X509_load_hook() {} + }; + +/************************************************* +* DL Private Key * +*************************************************/ +class DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, + public virtual PKCS8_PrivateKey + { + public: + bool check_key(bool) const; + + const BigInt& get_x() const { return x; } + + virtual ~DL_Scheme_PrivateKey() {} + protected: + BigInt x; + private: + SecureVector DER_encode_priv() const; + void BER_decode_priv(DataSource&); + + virtual void PKCS8_load_hook() {} + }; + +} + +#endif --- botan/dl_get.cpp +++ botan/dl_get.cpp @@ -0,0 +1,74 @@ +/************************************************* +* DL Group Lookup Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Name to group mapping table * +*************************************************/ +std::map dl_groups; +Mutex* dl_groups_lock = 0; + +} + +/************************************************* +* Try to obtain a particular DL group * +*************************************************/ +extern DL_Group try_to_get_dl_group(const std::string&); + +/************************************************* +* Retrieve a DL group by name * +*************************************************/ +const DL_Group& get_dl_group(const std::string& name) + { + initialize_mutex(dl_groups_lock); + Mutex_Holder lock(dl_groups_lock); + + std::map::const_iterator group; + group = dl_groups.find(name); + if(group != dl_groups.end()) + return group->second; + + dl_groups.insert(std::make_pair(name, try_to_get_dl_group(name))); + + group = dl_groups.find(name); + if(group != dl_groups.end()) + return group->second; + + throw Lookup_Error("DL group \"" + name + "\" not found"); + } + +/************************************************* +* Register a named DL group * +*************************************************/ +void add_dl_group(const std::string& name, const DL_Group& group) + { + initialize_mutex(dl_groups_lock); + Mutex_Holder lock(dl_groups_lock); + dl_groups.insert(std::make_pair(name, group)); + } + +namespace Init { + +/************************************************* +* Destroy the table * +*************************************************/ +void destroy_dl_groups() + { + dl_groups.clear(); + delete dl_groups_lock; + dl_groups_lock = 0; + } + +} + +} --- botan/dl_group.cpp +++ botan/dl_group.cpp @@ -0,0 +1,175 @@ +/************************************************* +* DL Groups Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +namespace { + +/************************************************* +* IETF 768-bit DL modulus * +*************************************************/ +const char* IETF_768_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF"; + +/************************************************* +* IETF 1024-bit DL modulus * +*************************************************/ +const char* IETF_1024_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" + "FFFFFFFF FFFFFFFF"; + +/************************************************* +* IETF 1536-bit DL modulus * +*************************************************/ +const char* IETF_1536_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF"; + +/************************************************* +* IETF 2048-bit DL modulus * +*************************************************/ +const char* IETF_2048_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"; + +/************************************************* +* IETF 3072-bit DL modulus * +*************************************************/ +const char* IETF_3072_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"; + +/************************************************* +* IETF 4096-bit DL modulus * +*************************************************/ +const char* IETF_4096_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" + "FFFFFFFF FFFFFFFF"; + +/************************************************* +* JCE seed/counter for 512-bit DSA modulus * +*************************************************/ +const char* JCE_512_SEED = "B869C82B 35D70E1B 1FF91B28 E37A62EC DC34409B"; +const u32bit JCE_512_COUNTER = 123; + +/************************************************* +* JCE seed/counter for 768-bit DSA modulus * +*************************************************/ +const char* JCE_768_SEED = "77D0F8C4 DAD15EB8 C4F2F8D6 726CEFD9 6D5BB399"; +const u32bit JCE_768_COUNTER = 263; + +/************************************************* +* JCE seed/counter for 1024-bit DSA modulus * +*************************************************/ +const char* JCE_1024_SEED = "8D515589 4229D5E6 89EE01E6 018A237E 2CAE64CD"; +const u32bit JCE_1024_COUNTER = 92; + +/************************************************* +* Decode the modulus string * +*************************************************/ +BigInt decode(const char* prime) + { + return BigInt::decode((const byte*)prime, std::strlen(prime), + BigInt::Hexadecimal); + } + +/************************************************* +* Decode the seed for DSA prime generation * +*************************************************/ +MemoryVector decode_seed(const std::string& hex_seed) + { + return OctetString(hex_seed).bits_of(); + } + +} + +/************************************************* +* Try to obtain a particular DL group * +*************************************************/ +DL_Group try_to_get_dl_group(const std::string& name) + { + if(name == "DSA-512") + return DL_Group(decode_seed(JCE_512_SEED), 512, JCE_512_COUNTER); + if(name == "DSA-768") + return DL_Group(decode_seed(JCE_768_SEED), 768, JCE_768_COUNTER); + if(name == "DSA-1024") + return DL_Group(decode_seed(JCE_1024_SEED), 1024, JCE_1024_COUNTER); + + BigInt p, q, g; + + if(name == "IETF-768") { g = 2; p = decode(IETF_768_PRIME); } + if(name == "IETF-1024") { g = 2; p = decode(IETF_1024_PRIME); } + if(name == "IETF-1536") { g = 2; p = decode(IETF_1536_PRIME); } + if(name == "IETF-2048") { g = 2; p = decode(IETF_2048_PRIME); } + if(name == "IETF-3072") { g = 2; p = decode(IETF_3072_PRIME); } + if(name == "IETF-4096") { g = 2; p = decode(IETF_4096_PRIME); } + + if(p > 0 && g > 0 && !q) + return DL_Group(p, g); + if(p > 0 && g > 0 && q > 0) + return DL_Group(p, q, g); + + throw Lookup_Error("DL group \"" + name + "\" not found"); + } + +} --- botan/dl_param.cpp +++ botan/dl_param.cpp @@ -0,0 +1,296 @@ +/************************************************* +* Discrete Logarithm Parameters Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group() + { + initialized = false; + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(u32bit pbits, PrimeType type) + { + if(pbits < 512) + throw Invalid_Argument("DL_Group: prime size " + to_string(pbits) + + " is too small"); + + if(type == Strong) + { + p = random_safe_prime(pbits, PublicValue); + q = (p - 1) / 2; + g = 2; + } + else if(type == Prime_Subgroup || type == DSA_Kosherizer) + { + if(type == Prime_Subgroup) + { + const u32bit qbits = 2 * dl_work_factor(pbits); + q = random_prime(qbits, PublicValue); + BigInt X; + while(p.bits() != pbits || !is_prime(p)) + { + X = random_integer(pbits, PublicValue); + p = X - (X % (2*q) - 1); + } + } + else + generate_dsa_primes(p, q, pbits); + + BigInt e = (p - 1) / q; + + for(u32bit j = 0; j != PRIME_TABLE_SIZE; j++) + { + g = power_mod(PRIMES[j], e, p); + if(g != 1) + break; + } + + if(g == 1) + throw Exception("DL_Group: Couldn't create a suitable generator"); + } + + initialized = true; + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(const MemoryRegion& seed, u32bit pbits, u32bit start) + { + if(!generate_dsa_primes(p, q, seed.begin(), seed.size(), pbits, start)) + throw Invalid_Argument("DL_Group: The seed/counter given does not " + "generate a DSA group"); + + BigInt e = (p - 1) / q; + + for(u32bit j = 0; j != PRIME_TABLE_SIZE; j++) + { + g = power_mod(PRIMES[j], e, p); + if(g != 1) + break; + } + + if(g == 1) + throw Exception("DL_Group: Couldn't create a suitable generator"); + + 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; + + if(q == 0 && check_prime((p - 1) / 2)) + q = (p - 1) / 2; + + 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(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)) + return false; + if((q > 0) && !check_prime(q)) + 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 Format_Error("DLP group has no q prime specified"); + return q; + } + +/************************************************* +* DER encode the parameters * +*************************************************/ +SecureVector 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"); + + DER_Encoder encoder; + encoder.start_sequence(); + if(format == ANSI_X9_57) + { + DER::encode(encoder, p); + DER::encode(encoder, q); + DER::encode(encoder, g); + } + else if(format == ANSI_X9_42) + { + DER::encode(encoder, p); + DER::encode(encoder, g); + DER::encode(encoder, q); + } + else if(format == PKCS_3) + { + DER::encode(encoder, p); + DER::encode(encoder, g); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + encoder.end_sequence(); + + return encoder.get_contents(); + } + +/************************************************* +* PEM encode the parameters * +*************************************************/ +std::string DL_Group::PEM_encode(Format format) const + { + SecureVector 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 " + to_string(format)); + } + +/************************************************* +* Decode BER encoded parameters * +*************************************************/ +void DL_Group::BER_decode(DataSource& source, Format format) + { + BigInt new_p, new_q, new_g; + + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + if(format == ANSI_X9_57) + { + BER::decode(sequence, new_p); + BER::decode(sequence, new_q); + BER::decode(sequence, new_g); + } + else if(format == ANSI_X9_42) + { + BER::decode(sequence, new_p); + BER::decode(sequence, new_g); + BER::decode(sequence, new_q); + sequence.discard_remaining(); + } + else if(format == PKCS_3) + { + BER::decode(sequence, new_p); + BER::decode(sequence, new_g); + sequence.discard_remaining(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + sequence.verify_end(); + + initialize(new_p, new_q, new_g); + } + +/************************************************* +* Decode PEM encoded parameters * +*************************************************/ +void DL_Group::PEM_decode(DataSource& source) + { + std::string label; + DataSource_Memory ber(PEM_Code::decode(source, 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); + } + +} --- botan/dl_param.h +++ botan/dl_param.h @@ -0,0 +1,58 @@ +/************************************************* +* Discrete Logarithm Group Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DL_PARM_H__ +#define BOTAN_DL_PARM_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Discrete Logarithm Group * +*************************************************/ +class DL_Group + { + public: + const BigInt& get_p() const; + const BigInt& get_q() const; + const BigInt& get_g() const; + + enum Format { ANSI_X9_42, ANSI_X9_57, PKCS_3 }; + enum PrimeType { Strong, Prime_Subgroup, DSA_Kosherizer }; + + bool verify_group(bool) const; + + std::string PEM_encode(Format) const; + SecureVector DER_encode(Format) const; + void BER_decode(DataSource&, Format); + void PEM_decode(DataSource&); + + DL_Group(); + DL_Group(u32bit, PrimeType = Strong); + DL_Group(const MemoryRegion&, u32bit = 1024, u32bit = 0); + DL_Group(const BigInt&, const BigInt&); + DL_Group(const BigInt&, const BigInt&, const BigInt&); + private: + void init_check() const; + void initialize(const BigInt&, const BigInt&, const BigInt&); + bool initialized; + BigInt p, q, g; + }; + +/************************************************* +* Retrieve a DL group by name * +*************************************************/ +const DL_Group& get_dl_group(const std::string&); + +/************************************************* +* Register a named DL group * +*************************************************/ +void add_dl_group(const std::string&, const DL_Group&); + +} + +#endif --- botan/dlies.cpp +++ botan/dlies.cpp @@ -0,0 +1,127 @@ +/************************************************* +* DLIES Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* DLIES_Encryptor Constructor * +*************************************************/ +DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& k, + const std::string& kdf, + const std::string& mac, u32bit mk_len) : + key(k), kdf_algo(kdf), mac_algo(mac), MAC_KEYLEN(mk_len) + { + } + +/************************************************* +* DLIES Encryption * +*************************************************/ +SecureVector DLIES_Encryptor::enc(const byte in[], u32bit length) const + { + if(length > maximum_input_size()) + throw Invalid_Argument("DLIES: Plaintext too large"); + if(other_key.is_empty()) + throw Invalid_State("DLIES: The other key was never set"); + + std::auto_ptr kdf(get_kdf(kdf_algo)); + std::auto_ptr mac(get_mac(mac_algo)); + + MemoryVector v = key.public_value(); + + SecureVector out(v.size() + length + mac->OUTPUT_LENGTH); + out.copy(v, v.size()); + out.copy(v.size(), in, length); + + SecureVector vz(v, key.derive_key(other_key, other_key.size())); + + const u32bit K_LENGTH = length + MAC_KEYLEN; + OctetString K = kdf->derive_key(K_LENGTH, vz, vz.size()); + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + byte* C = out + v.size(); + + xor_buf(C, K.begin() + MAC_KEYLEN, length); + mac->set_key(K.begin(), MAC_KEYLEN); + + mac->update(C, length); + for(u32bit j = 0; j != 8; j++) + mac->update(0); + + mac->final(C + length); + + return out; + } + +/************************************************* +* Set the other parties public key * +*************************************************/ +void DLIES_Encryptor::set_other_key(const MemoryRegion& ok) + { + other_key = ok; + } + +/************************************************* +* Return the max size, in bytes, of a message * +*************************************************/ +u32bit DLIES_Encryptor::maximum_input_size() const + { + return 32; + } + +/************************************************* +* DLIES_Decryptor Constructor * +*************************************************/ +DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& k, + const std::string& kdf, + const std::string& mac, u32bit mk_len) : + key(k), kdf_algo(kdf), mac_algo(mac), + MAC_KEYLEN(mk_len), PUBLIC_LEN(key.public_value().size()) + { + } + +/************************************************* +* DLIES Decryption * +*************************************************/ +SecureVector DLIES_Decryptor::dec(const byte msg[], u32bit length) const + { + std::auto_ptr mac(get_mac(mac_algo)); + + if(length < PUBLIC_LEN + mac->OUTPUT_LENGTH) + throw Decoding_Error("DLIES decryption: ciphertext is too short"); + + std::auto_ptr kdf(get_kdf(kdf_algo)); + + const u32bit CIPHER_LEN = length - PUBLIC_LEN - mac->OUTPUT_LENGTH; + + SecureVector v(msg, PUBLIC_LEN); + SecureVector C(msg + PUBLIC_LEN, CIPHER_LEN); + SecureVector T(msg + PUBLIC_LEN + CIPHER_LEN, mac->OUTPUT_LENGTH); + + SecureVector vz(v, key.derive_key(v, v.size())); + + const u32bit K_LENGTH = C.size() + MAC_KEYLEN; + OctetString K = kdf->derive_key(K_LENGTH, vz, vz.size()); + 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(u32bit j = 0; j != 8; j++) + mac->update(0); + SecureVector T2 = mac->final(); + if(T != T2) + throw Integrity_Failure("DLIES: message authentication failed"); + + xor_buf(C, K.begin() + MAC_KEYLEN, C.size()); + + return C; + } + +} --- botan/dlies.h +++ botan/dlies.h @@ -0,0 +1,52 @@ +/************************************************* +* DLIES Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_DLIES_H__ +#define BOTAN_DLIES_H__ + +#include + +namespace Botan { + +/************************************************* +* DLIES Encryption * +*************************************************/ +class DLIES_Encryptor : public PK_Encryptor + { + public: + DLIES_Encryptor(const PK_Key_Agreement_Key&, + const std::string& = "KDF2(SHA-160)", + const std::string& = "HMAC(SHA-160)", u32bit = 20); + void set_other_key(const MemoryRegion&); + private: + SecureVector enc(const byte[], u32bit) const; + u32bit maximum_input_size() const; + const PK_Key_Agreement_Key& key; + SecureVector other_key; + const std::string kdf_algo; + const std::string mac_algo; + const u32bit MAC_KEYLEN; + }; + +/************************************************* +* DLIES Decryption * +*************************************************/ +class DLIES_Decryptor : public PK_Decryptor + { + public: + DLIES_Decryptor(const PK_Key_Agreement_Key&, + const std::string& = "KDF2(SHA-160)", + const std::string& = "HMAC(SHA-160)", u32bit = 20); + private: + SecureVector dec(const byte[], u32bit) const; + const PK_Key_Agreement_Key& key; + const std::string kdf_algo; + const std::string mac_algo; + const u32bit MAC_KEYLEN, PUBLIC_LEN; + }; + +} + +#endif --- botan/eax.cpp +++ botan/eax.cpp @@ -0,0 +1,303 @@ +/************************************************* +* EAX Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* EAX OMAC-based PRF * +*************************************************/ +SecureVector omac_n(byte param, u32bit BLOCK_SIZE, + MessageAuthenticationCode* omac, + const byte in[], u32bit length) + { + for(u32bit j = 0; j != BLOCK_SIZE - 1; j++) + omac->update(0); + omac->update(param); + omac->update(in, length); + return omac->final(); + } + +} + +/************************************************* +* EAX_Base Constructor * +*************************************************/ +EAX_Base::EAX_Base(const std::string& cipher_name, + u32bit tag_size) : + TAG_SIZE(tag_size ? tag_size / 8 : block_size_of(cipher_name)), + BLOCK_SIZE(block_size_of(cipher_name)) + { + const std::string omac_name = "OMAC(" + cipher_name + ")"; + + cipher = get_block_cipher(cipher_name); + omac = get_mac(omac_name); + + if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > omac->OUTPUT_LENGTH) + throw Invalid_Argument(name() + ": Bad tag size " + to_string(tag_size)); + + state.create(BLOCK_SIZE); + buffer.create(BLOCK_SIZE); + position = 0; + } + +/************************************************* +* Check if a keylength is valid for EAX * +*************************************************/ +bool EAX_Base::valid_keylength(u32bit n) const + { + if(!cipher->valid_keylength(n)) + return false; + if(!omac->valid_keylength(n)) + return false; + return true; + } + +/************************************************* +* Set the EAX key * +*************************************************/ +void EAX_Base::set_key(const SymmetricKey& key) + { + cipher->set_key(key); + omac->set_key(key); + header_mac = omac_n(1, BLOCK_SIZE, omac, 0, 0); + } + +/************************************************* +* Do setup at the start of each message * +*************************************************/ +void EAX_Base::start_msg() + { + for(u32bit j = 0; j != BLOCK_SIZE - 1; j++) + omac->update(0); + omac->update(2); + } + +/************************************************* +* Set the EAX nonce * +*************************************************/ +void EAX_Base::set_iv(const InitializationVector& iv) + { + nonce_mac = omac_n(0, BLOCK_SIZE, omac, iv.begin(), iv.length()); + state = nonce_mac; + cipher->encrypt(state, buffer); + } + +/************************************************* +* Set the EAX header * +*************************************************/ +void EAX_Base::set_header(const byte header[], u32bit length) + { + header_mac = omac_n(1, BLOCK_SIZE, omac, header, length); + } + +/************************************************* +* Return the name of this cipher mode * +*************************************************/ +std::string EAX_Base::name() const + { + return (cipher->name() + "/EAX"); + } + +/************************************************* +* Increment the counter and update the buffer * +*************************************************/ +void EAX_Base::increment_counter() + { + for(s32bit j = BLOCK_SIZE - 1; j >= 0; j--) + if(++state[j]) + break; + cipher->encrypt(state, buffer); + position = 0; + } + +/************************************************* +* EAX_Encryption Constructor * +*************************************************/ +EAX_Encryption::EAX_Encryption(const std::string& cipher_name, + u32bit tag_size) : + EAX_Base(cipher_name, tag_size) + { + } + +/************************************************* +* EAX_Encryption Constructor * +*************************************************/ +EAX_Encryption::EAX_Encryption(const std::string& cipher_name, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit tag_size) : + EAX_Base(cipher_name, tag_size) + { + set_key(key); + set_iv(iv); + } + +/************************************************* +* Encrypt in EAX mode * +*************************************************/ +void EAX_Encryption::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer + position, input, copied); + send(buffer + position, copied); + omac->update(buffer + position, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + increment_counter(); + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + omac->update(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + increment_counter(); + } + + xor_buf(buffer + position, input, length); + send(buffer + position, length); + omac->update(buffer + position, length); + position += length; + } + +/************************************************* +* Finish encrypting in EAX mode * +*************************************************/ +void EAX_Encryption::end_msg() + { + SecureVector data_mac = omac->final(); + xor_buf(data_mac, nonce_mac, data_mac.size()); + xor_buf(data_mac, header_mac, data_mac.size()); + + send(data_mac, TAG_SIZE); + + state.clear(); + buffer.clear(); + position = 0; + } + +/************************************************* +* EAX_Decryption Constructor * +*************************************************/ +EAX_Decryption::EAX_Decryption(const std::string& cipher_name, + u32bit tag_size) : + EAX_Base(cipher_name, tag_size) + { + queue.create(2*TAG_SIZE + DEFAULT_BUFFERSIZE); + queue_start = queue_end = 0; + } + +/************************************************* +* EAX_Decryption Constructor * +*************************************************/ +EAX_Decryption::EAX_Decryption(const std::string& cipher_name, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit tag_size) : + EAX_Base(cipher_name, tag_size) + { + set_key(key); + set_iv(iv); + queue.create(2*TAG_SIZE + DEFAULT_BUFFERSIZE); + queue_start = queue_end = 0; + } + +/************************************************* +* Decrypt in EAX mode * +*************************************************/ +void EAX_Decryption::write(const byte input[], u32bit length) + { + while(length) + { + const u32bit copied = std::min(length, queue.size() - queue_end); + + queue.copy(queue_end, input, copied); + input += copied; + length -= copied; + queue_end += copied; + + SecureVector block_buf(cipher->BLOCK_SIZE); + while((queue_end - queue_start) > TAG_SIZE) + { + u32bit removed = (queue_end - queue_start) - TAG_SIZE; + do_write(queue + queue_start, removed); + queue_start += removed; + } + + if(queue_start + TAG_SIZE == queue_end && + queue_start >= queue.size() / 2) + { + SecureVector queue_data(TAG_SIZE); + queue_data.copy(queue + queue_start, TAG_SIZE); + queue.copy(queue_data, TAG_SIZE); + queue_start = 0; + queue_end = TAG_SIZE; + } + } + } + +/************************************************* +* Decrypt in EAX mode * +*************************************************/ +void EAX_Decryption::do_write(const byte input[], u32bit length) + { + omac->update(input, length); + + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer + position, input, copied); + send(buffer + position, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + increment_counter(); + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + increment_counter(); + } + + xor_buf(buffer + position, input, length); + send(buffer + position, length); + position += length; + } + +/************************************************* +* Finish decrypting in EAX mode * +*************************************************/ +void EAX_Decryption::end_msg() + { + if((queue_end - queue_start) != TAG_SIZE) + throw Integrity_Failure(name() + ": Message authentication failure"); + + SecureVector data_mac = omac->final(); + + for(u32bit j = 0; j != TAG_SIZE; j++) + if(queue[queue_start+j] != (data_mac[j] ^ nonce_mac[j] ^ header_mac[j])) + throw Integrity_Failure(name() + ": Message authentication failure"); + + state.clear(); + buffer.clear(); + position = 0; + queue_start = queue_end = 0; + } + +} --- botan/eax.h +++ botan/eax.h @@ -0,0 +1,72 @@ +/************************************************* +* EAX Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EAX_H__ +#define BOTAN_EAX_H__ + +#include + +namespace Botan { + +/************************************************* +* EAX Base Class * +*************************************************/ +class EAX_Base : public Keyed_Filter + { + public: + void set_key(const SymmetricKey&); + void set_iv(const InitializationVector&); + void set_header(const byte[], u32bit); + std::string name() const; + + bool valid_keylength(u32bit) const; + + ~EAX_Base() { delete cipher; delete omac; } + protected: + EAX_Base(const std::string&, u32bit); + void start_msg(); + void increment_counter(); + + const u32bit TAG_SIZE, BLOCK_SIZE; + BlockCipher* cipher; + MessageAuthenticationCode* omac; + SecureVector nonce_mac, header_mac, state, buffer; + u32bit position; + }; + +/************************************************* +* EAX Encryption * +*************************************************/ +class EAX_Encryption : public EAX_Base + { + public: + EAX_Encryption(const std::string&, u32bit = 0); + EAX_Encryption(const std::string&, const SymmetricKey&, + const InitializationVector&, u32bit = 0); + private: + void write(const byte[], u32bit); + void end_msg(); + }; + +/************************************************* +* EAX Decryption * +*************************************************/ +class EAX_Decryption : public EAX_Base + { + public: + EAX_Decryption(const std::string&, u32bit = 0); + EAX_Decryption(const std::string&, const SymmetricKey&, + const InitializationVector&, u32bit = 0); + private: + void write(const byte[], u32bit); + void do_write(const byte[], u32bit); + void end_msg(); + SecureVector queue; + u32bit queue_start, queue_end; + }; + +} + +#endif --- botan/ecb.cpp +++ botan/ecb.cpp @@ -0,0 +1,152 @@ +/************************************************* +* ECB Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* ECB Constructor * +*************************************************/ +ECB::ECB(const std::string& cipher_name, const std::string& padding_name) : + BlockCipherMode(cipher_name, "ECB", 0), padder(get_bc_pad(padding_name)) + { + } + +/************************************************* +* Verify the IV is not set * +*************************************************/ +bool ECB::valid_iv_size(u32bit iv_size) const + { + if(iv_size == 0) + return true; + return false; + } + +/************************************************* +* Return an ECB mode name * +*************************************************/ +std::string ECB::name() const + { + return (cipher->name() + "/" + mode_name + "/" + padder->name()); + } + +/************************************************* +* ECB Encryption Constructor * +*************************************************/ +ECB_Encryption::ECB_Encryption(const std::string& cipher_name, + const std::string& padding_name) : + ECB(cipher_name, padding_name) + { + } + +/************************************************* +* ECB Encryption Constructor * +*************************************************/ +ECB_Encryption::ECB_Encryption(const std::string& cipher_name, + const std::string& padding_name, + const SymmetricKey& key) : + ECB(cipher_name, padding_name) + { + set_key(key); + } + +/************************************************* +* Encrypt in ECB mode * +*************************************************/ +void ECB_Encryption::write(const byte input[], u32bit length) + { + buffer.copy(position, input, length); + if(position + length >= BLOCK_SIZE) + { + cipher->encrypt(buffer); + send(buffer, BLOCK_SIZE); + input += (BLOCK_SIZE - position); + length -= (BLOCK_SIZE - position); + while(length >= BLOCK_SIZE) + { + cipher->encrypt(input, buffer); + send(buffer, BLOCK_SIZE); + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/************************************************* +* Finish encrypting in ECB mode * +*************************************************/ +void ECB_Encryption::end_msg() + { + SecureVector padding(BLOCK_SIZE); + padder->pad(padding, padding.size(), position); + write(padding, padder->pad_bytes(BLOCK_SIZE, position)); + if(position != 0) + throw Encoding_Error(name() + ": Did not pad to full blocksize"); + } + +/************************************************* +* ECB Decryption Constructor * +*************************************************/ +ECB_Decryption::ECB_Decryption(const std::string& cipher_name, + const std::string& padding_name) : + ECB(cipher_name, padding_name) + { + } + +/************************************************* +* ECB Decryption Constructor * +*************************************************/ +ECB_Decryption::ECB_Decryption(const std::string& cipher_name, + const std::string& padding_name, + const SymmetricKey& key) : + ECB(cipher_name, padding_name) + { + set_key(key); + } + +/************************************************* +* Decrypt in ECB mode * +*************************************************/ +void ECB_Decryption::write(const byte input[], u32bit length) + { + buffer.copy(position, input, length); + if(position + length > BLOCK_SIZE) + { + cipher->decrypt(buffer); + send(buffer, BLOCK_SIZE); + input += (BLOCK_SIZE - position); + length -= (BLOCK_SIZE - position); + while(length > BLOCK_SIZE) + { + cipher->decrypt(input, buffer); + send(buffer, BLOCK_SIZE); + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/************************************************* +* Finish decrypting in ECB mode * +*************************************************/ +void ECB_Decryption::end_msg() + { + if(position != BLOCK_SIZE) + throw Decoding_Error(name()); + cipher->decrypt(buffer); + send(buffer, padder->unpad(buffer, BLOCK_SIZE)); + state = buffer; + position = 0; + } + +} --- botan/ecb.h +++ botan/ecb.h @@ -0,0 +1,57 @@ +/************************************************* +* ECB Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ECB_H__ +#define BOTAN_ECB_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* ECB * +*************************************************/ +class ECB : public BlockCipherMode + { + protected: + ECB(const std::string&, const std::string&); + std::string name() const; + const BlockCipherModePaddingMethod* padder; + private: + bool valid_iv_size(u32bit) const; + }; + +/************************************************* +* ECB Encryption * +*************************************************/ +class ECB_Encryption : public ECB + { + public: + ECB_Encryption(const std::string&, const std::string&); + ECB_Encryption(const std::string&, const std::string&, + const SymmetricKey&); + private: + void write(const byte[], u32bit); + void end_msg(); + }; + +/************************************************* +* ECB Decryption * +*************************************************/ +class ECB_Decryption : public ECB + { + public: + ECB_Decryption(const std::string&, const std::string&); + ECB_Decryption(const std::string&, const std::string&, + const SymmetricKey&); + private: + void write(const byte[], u32bit); + void end_msg(); + }; + +} + +#endif --- botan/eme.h +++ botan/eme.h @@ -0,0 +1,45 @@ +/************************************************* +* EME Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EME_H__ +#define BOTAN_EME_H__ + +#include + +namespace Botan { + +/************************************************* +* EME1 * +*************************************************/ +class EME1 : public EME + { + public: + u32bit maximum_input_size(u32bit) const; + + EME1(const std::string&, const std::string&, const std::string& = ""); + ~EME1() { delete mgf; } + private: + SecureVector pad(const byte[], u32bit, u32bit) const; + SecureVector unpad(const byte[], u32bit, u32bit) const; + const u32bit HASH_LENGTH; + SecureVector Phash; + MGF* mgf; + }; + +/************************************************* +* EME_PKCS1v15 * +*************************************************/ +class EME_PKCS1v15 : public EME + { + public: + u32bit maximum_input_size(u32bit) const; + private: + SecureVector pad(const byte[], u32bit, u32bit) const; + SecureVector unpad(const byte[], u32bit, u32bit) const; + }; + +} + +#endif --- botan/eme1.cpp +++ botan/eme1.cpp @@ -0,0 +1,96 @@ +/************************************************* +* EME1 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* EME1 Pad Operation * +*************************************************/ +SecureVector EME1::pad(const byte in[], u32bit in_length, + u32bit key_length) const + { + key_length /= 8; + + if(in_length > key_length - 2*HASH_LENGTH - 1) + throw Exception("EME1: Input is too large"); + + SecureVector out(key_length); + + out.clear(); + + Global_RNG::randomize(out, HASH_LENGTH, Nonce); + + out.copy(HASH_LENGTH, Phash, Phash.size()); + out[out.size() - in_length - 1] = 0x01; + out.copy(out.size() - in_length, in, in_length); + mgf->mask(out, HASH_LENGTH, out + HASH_LENGTH, out.size() - HASH_LENGTH); + mgf->mask(out + HASH_LENGTH, out.size() - HASH_LENGTH, out, HASH_LENGTH); + + return out; + } + +/************************************************* +* EME1 Unpad Operation * +*************************************************/ +SecureVector EME1::unpad(const byte in[], u32bit in_length, + u32bit key_length) const + { + key_length /= 8; + if(in_length > key_length) + throw Decoding_Error("Invalid EME1 encoding"); + + SecureVector tmp(key_length); + tmp.copy(key_length - in_length, in, in_length); + + mgf->mask(tmp + HASH_LENGTH, tmp.size() - HASH_LENGTH, tmp, HASH_LENGTH); + mgf->mask(tmp, HASH_LENGTH, tmp + HASH_LENGTH, tmp.size() - HASH_LENGTH); + + for(u32bit j = 0; j != Phash.size(); j++) + if(tmp[j+HASH_LENGTH] != Phash[j]) + throw Decoding_Error("Invalid EME1 encoding"); + + for(u32bit j = HASH_LENGTH + Phash.size(); j != tmp.size(); j++) + { + if(tmp[j] && tmp[j] != 0x01) + throw Decoding_Error("Invalid EME1 encoding"); + if(tmp[j] && tmp[j] == 0x01) + { + SecureVector retval(tmp + j + 1, tmp.size() - j - 1); + return retval; + } + } + throw Decoding_Error("Invalid EME1 encoding"); + } + +/************************************************* +* Return the max input size for a given key size * +*************************************************/ +u32bit EME1::maximum_input_size(u32bit keybits) const + { + if(keybits / 8 > 2*HASH_LENGTH + 1) + return ((keybits / 8) - 2*HASH_LENGTH - 1); + else + return 0; + } + +/************************************************* +* EME1 Constructor * +*************************************************/ +EME1::EME1(const std::string& hash_name, const std::string& mgf_name, + const std::string& P) : + HASH_LENGTH(output_length_of(hash_name)) + { + mgf = get_mgf(mgf_name + "(" + hash_name + ")"); + std::auto_ptr hash(get_hash(hash_name)); + Phash = hash->process(P); + } + +} --- botan/eme_pkcs.cpp +++ botan/eme_pkcs.cpp @@ -0,0 +1,68 @@ +/************************************************* +* PKCS1 EME Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* PKCS1 Pad Operation * +*************************************************/ +SecureVector EME_PKCS1v15::pad(const byte in[], u32bit inlen, + u32bit olen) 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"); + + SecureVector out(olen); + + out[0] = 0x02; + for(u32bit j = 1; j != olen - inlen - 1; j++) + while(out[j] == 0) + out[j] = Global_RNG::random(Nonce); + out.copy(olen - inlen, in, inlen); + + return out; + } + +/************************************************* +* PKCS1 Unpad Operation * +*************************************************/ +SecureVector EME_PKCS1v15::unpad(const byte in[], u32bit inlen, + u32bit key_len) const + { + if(inlen != key_len / 8 || inlen < 10 || in[0] != 0x02) + throw Decoding_Error("PKCS1::unpad"); + + u32bit seperator = 0; + for(u32bit j = 0; j != inlen; j++) + if(in[j] == 0) + { + seperator = j; + break; + } + if(seperator < 9) + throw Decoding_Error("PKCS1::unpad"); + + return SecureVector(in + seperator + 1, inlen - seperator - 1); + } + +/************************************************* +* Return the max input size for a given key size * +*************************************************/ +u32bit EME_PKCS1v15::maximum_input_size(u32bit keybits) const + { + if(keybits / 8 > 10) + return ((keybits / 8) - 10); + else + return 0; + } + +} --- botan/emsa.h +++ botan/emsa.h @@ -0,0 +1,97 @@ +/************************************************* +* EMSA Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EMSA_H__ +#define BOTAN_EMSA_H__ + +#include + +namespace Botan { + +/************************************************* +* EMSA1 * +*************************************************/ +class EMSA1 : public EMSA + { + public: + EMSA1(const std::string&); + ~EMSA1() { delete hash; } + private: + void update(const byte[], u32bit); + SecureVector encoding_of(const MemoryRegion&, u32bit); + SecureVector raw_data(); + bool verify(const MemoryRegion&, const MemoryRegion&, + u32bit) throw(); + HashFunction* hash; + }; + +/************************************************* +* EMSA2 * +*************************************************/ +class EMSA2 : public EMSA + { + public: + EMSA2(const std::string&); + ~EMSA2() { delete hash; } + private: + void update(const byte[], u32bit); + SecureVector encoding_of(const MemoryRegion&, u32bit); + SecureVector raw_data(); + SecureVector empty_hash; + HashFunction* hash; + byte hash_id; + }; + +/************************************************* +* EMSA3 * +*************************************************/ +class EMSA3 : public EMSA + { + public: + EMSA3(const std::string&); + ~EMSA3() { delete hash; } + private: + void update(const byte[], u32bit); + SecureVector encoding_of(const MemoryRegion&, u32bit); + SecureVector raw_data(); + HashFunction* hash; + SecureVector hash_id; + }; + +/************************************************* +* EMSA4 * +*************************************************/ +class EMSA4 : public EMSA + { + public: + EMSA4(const std::string&, const std::string&); + EMSA4(const std::string&, const std::string&, u32bit); + ~EMSA4() { delete hash; delete mgf; } + private: + void update(const byte[], u32bit); + SecureVector encoding_of(const MemoryRegion&, u32bit); + SecureVector raw_data(); + bool verify(const MemoryRegion&, const MemoryRegion&, + u32bit) throw(); + const u32bit SALT_SIZE; + HashFunction* hash; + const MGF* mgf; + }; + +/************************************************* +* EMSA-Raw * +*************************************************/ +class EMSA_Raw : public EMSA + { + private: + void update(const byte[], u32bit); + SecureVector encoding_of(const MemoryRegion&, u32bit); + SecureVector raw_data(); + SecureVector message; + }; + +} + +#endif --- botan/emsa1.cpp +++ botan/emsa1.cpp @@ -0,0 +1,98 @@ +/************************************************* +* EMSA1 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* EMSA1 Update Operation * +*************************************************/ +void EMSA1::update(const byte input[], u32bit length) + { + hash->update(input, length); + } + +/************************************************* +* Return the raw (unencoded) data * +*************************************************/ +SecureVector EMSA1::raw_data() + { + return hash->final(); + } + +/************************************************* +* EMSA1 Encode Operation * +*************************************************/ +SecureVector EMSA1::encoding_of(const MemoryRegion& msg, + u32bit output_bits) + { + if(msg.size() != hash->OUTPUT_LENGTH) + throw Invalid_Argument("EMSA1::encoding_of: Invalid size for input"); + if(msg.bits() <= output_bits) + return msg; + + u32bit shift = msg.bits() - output_bits; + + u32bit byte_shift = shift / 8, bit_shift = shift % 8; + SecureVector digest(msg.size() - byte_shift); + + for(u32bit j = 0; j != msg.size() - byte_shift; j++) + digest[j] = msg[j]; + + if(bit_shift) + { + byte carry = 0; + for(u32bit j = 0; j != digest.size(); j++) + { + byte temp = digest[j]; + digest[j] = (temp >> bit_shift) | carry; + carry = (temp << (8 - bit_shift)); + } + } + return digest; + } + +/************************************************* +* EMSA1 Decode/Verify Operation * +*************************************************/ +bool EMSA1::verify(const MemoryRegion& coded, + const MemoryRegion& raw, u32bit key_bits) throw() + { + try { + SecureVector our_coding = encoding_of(raw, key_bits); + + if(our_coding == coded) return true; + if(our_coding[0] != 0) return false; + if(our_coding.size() <= coded.size()) return false; + + u32bit offset = 0; + while(our_coding[offset] == 0 && offset < our_coding.size()) + offset++; + if(our_coding.size() - offset != coded.size()) + return false; + + for(u32bit j = 0; j != coded.size(); j++) + if(coded[j] != our_coding[j+offset]) + return false; + + return true; + } + catch(Invalid_Argument) + { + return false; + } + } + +/************************************************* +* EMSA1 Constructor * +*************************************************/ +EMSA1::EMSA1(const std::string& hash_name) : + hash(get_hash(hash_name)) + { + } + +} --- botan/emsa2.cpp +++ botan/emsa2.cpp @@ -0,0 +1,69 @@ +/************************************************* +* EMSA2 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* EMSA2 Update Operation * +*************************************************/ +void EMSA2::update(const byte input[], u32bit length) + { + hash->update(input, length); + } + +/************************************************* +* Return the raw (unencoded) data * +*************************************************/ +SecureVector EMSA2::raw_data() + { + return hash->final(); + } + +/************************************************* +* EMSA2 Encode Operation * +*************************************************/ +SecureVector EMSA2::encoding_of(const MemoryRegion& msg, + u32bit output_bits) + { + u32bit output_length = (output_bits + 1) / 8; + + if(msg.size() != hash->OUTPUT_LENGTH) + throw Invalid_Argument("EMSA2::encoding_of: Bad input length"); + if(output_length < hash->OUTPUT_LENGTH + 4) + throw Invalid_Argument("EMSA2::encoding_of: Output length is too small"); + + bool empty = true; + for(u32bit j = 0; j != hash->OUTPUT_LENGTH; j++) + if(empty_hash[j] != msg[j]) + empty = false; + + SecureVector output(output_length); + + output[0] = (empty ? 0x4B : 0x6B); + output[output_length - 3 - hash->OUTPUT_LENGTH] = 0xBA; + set_mem(output + 1, output_length - 4 - hash->OUTPUT_LENGTH, 0xBB); + output.copy(output_length-2-hash->OUTPUT_LENGTH, msg, msg.size()); + output[output_length-2] = hash_id; + output[output_length-1] = 0xCC; + + return output; + } + +/************************************************* +* EMSA2 Constructor * +*************************************************/ +EMSA2::EMSA2(const std::string& hash_name) + { + hash_id = ieee1363_hash_id(hash_name); + if(hash_id == 0) + throw Invalid_Argument("EMSA2 cannot be used with " + hash->name()); + hash = get_hash(hash_name); + empty_hash = hash->final(); + } + +} --- botan/emsa3.cpp +++ botan/emsa3.cpp @@ -0,0 +1,63 @@ +/************************************************* +* EMSA3 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* EMSA3 Update Operation * +*************************************************/ +void EMSA3::update(const byte input[], u32bit length) + { + hash->update(input, length); + } + +/************************************************* +* Return the raw (unencoded) data * +*************************************************/ +SecureVector EMSA3::raw_data() + { + return hash->final(); + } + +/************************************************* +* EMSA3 Encode Operation * +*************************************************/ +SecureVector EMSA3::encoding_of(const MemoryRegion& msg, + u32bit output_bits) + { + if(msg.size() != hash->OUTPUT_LENGTH) + throw Invalid_Argument("EMSA3::encoding_of: Bad input length"); + + u32bit output_length = output_bits / 8; + if(output_length < hash_id.size() + hash->OUTPUT_LENGTH + 10) + throw Invalid_Argument("EMSA3::pad: Output length is too small"); + + SecureVector T(output_length); + const u32bit P_LENGTH = output_length - hash->OUTPUT_LENGTH - + hash_id.size() - 2; + + T[0] = 0x01; + set_mem(T+1, P_LENGTH, 0xFF); + T[P_LENGTH+1] = 0x00; + T.copy(P_LENGTH+2, hash_id, hash_id.size()); + T.copy(output_length-hash->OUTPUT_LENGTH, msg, msg.size()); + return T; + } + +/************************************************* +* EMSA3 Constructor * +*************************************************/ +EMSA3::EMSA3(const std::string& hash_name) + { + hash_id = pkcs_hash_id(hash_name); + if(hash_id.is_empty()) + throw Invalid_Argument("EMSA3 cannot be used with " + hash_name); + hash = get_hash(hash_name); + } + +} --- botan/emsa4.cpp +++ botan/emsa4.cpp @@ -0,0 +1,143 @@ +/************************************************* +* EMSA4 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* EMSA4 Update Operation * +*************************************************/ +void EMSA4::update(const byte input[], u32bit length) + { + hash->update(input, length); + } + +/************************************************* +* Return the raw (unencoded) data * +*************************************************/ +SecureVector EMSA4::raw_data() + { + return hash->final(); + } + +/************************************************* +* EMSA4 Encode Operation * +*************************************************/ +SecureVector EMSA4::encoding_of(const MemoryRegion& msg, + u32bit output_bits) + { + const u32bit HASH_SIZE = hash->OUTPUT_LENGTH; + + if(msg.size() != HASH_SIZE) + throw Invalid_Argument("EMSA4::encoding_of: Bad input length"); + if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9) + throw Invalid_Argument("EMSA4::pad: Output length is too small"); + + const u32bit output_length = (output_bits + 7) / 8; + + SecureVector salt(SALT_SIZE); + Global_RNG::randomize(salt, SALT_SIZE, Nonce); + + for(u32bit j = 0; j != 8; j++) + hash->update(0); + hash->update(msg); + hash->update(salt, SALT_SIZE); + SecureVector H = hash->final(); + + SecureVector EM(output_length); + + EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01; + EM.copy(output_length - 1 - HASH_SIZE - SALT_SIZE, salt, SALT_SIZE); + mgf->mask(H, HASH_SIZE, EM, output_length - HASH_SIZE - 1); + EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); + EM.copy(output_length - 1 - HASH_SIZE, H, HASH_SIZE); + EM[output_length-1] = 0xBC; + + return EM; + } + +/************************************************* +* EMSA4 Decode/Verify Operation * +*************************************************/ +bool EMSA4::verify(const MemoryRegion& const_coded, + const MemoryRegion& raw, u32bit key_bits) throw() + { + const u32bit HASH_SIZE = hash->OUTPUT_LENGTH; + const u32bit 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) + return false; + if(const_coded[const_coded.size()-1] != 0xBC) + return false; + + SecureVector coded = const_coded; + if(coded.size() < KEY_BYTES) + { + SecureVector temp(KEY_BYTES); + temp.copy(KEY_BYTES - coded.size(), coded, coded.size()); + coded = temp; + } + + const u32bit TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; + if(TOP_BITS > 8 - high_bit(coded[0])) + return false; + + SecureVector DB(coded.begin(), coded.size() - HASH_SIZE - 1); + SecureVector H(coded + coded.size() - HASH_SIZE - 1, HASH_SIZE); + + mgf->mask(H, H.size(), DB, coded.size() - H.size() - 1); + DB[0] &= 0xFF >> TOP_BITS; + + u32bit salt_offset = 0; + for(u32bit 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; + + SecureVector salt(DB + salt_offset, DB.size() - salt_offset); + + for(u32bit j = 0; j != 8; j++) + hash->update(0); + hash->update(raw); + hash->update(salt); + SecureVector H2 = hash->final(); + + return (H == H2); + } + +/************************************************* +* EMSA4 Constructor * +*************************************************/ +EMSA4::EMSA4(const std::string& hash_name, const std::string& mgf_name) : + SALT_SIZE(output_length_of(hash_name)) + { + hash = get_hash(hash_name); + mgf = get_mgf(mgf_name + "(" + hash_name + ")"); + } + +/************************************************* +* EMSA4 Constructor * +*************************************************/ +EMSA4::EMSA4(const std::string& hash_name, const std::string& mgf_name, + u32bit salt_size) : SALT_SIZE(salt_size) + { + hash = get_hash(hash_name); + mgf = get_mgf(mgf_name + "(" + hash_name + ")"); + } + +} --- botan/emsa_raw.cpp +++ botan/emsa_raw.cpp @@ -0,0 +1,37 @@ +/************************************************* +* EMSA-Raw Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* EMSA-Raw Encode Operation * +*************************************************/ +void EMSA_Raw::update(const byte input[], u32bit length) + { + message.append(input, length); + } + +/************************************************* +* Return the raw (unencoded) data * +*************************************************/ +SecureVector EMSA_Raw::raw_data() + { + SecureVector buf = message; + message.destroy(); + return buf; + } + +/************************************************* +* EMSA-Raw Encode Operation * +*************************************************/ +SecureVector EMSA_Raw::encoding_of(const MemoryRegion& msg, + u32bit) + { + return msg; + } + +} --- botan/eng_base.cpp +++ botan/eng_base.cpp @@ -0,0 +1,274 @@ +/************************************************* +* Basic No-Op Engine Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +IF_Operation* Engine::if_op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +DSA_Operation* Engine::dsa_op(const DL_Group&, const BigInt&, + const BigInt&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +NR_Operation* Engine::nr_op(const DL_Group&, const BigInt&, + const BigInt&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +ELG_Operation* Engine::elg_op(const DL_Group&, const BigInt&, + const BigInt&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +DH_Operation* Engine::dh_op(const DL_Group&, const BigInt&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +ModularReducer* Engine::reducer(const BigInt&, bool) const + { + return 0; + } + +/************************************************* +* Acquire a BlockCipher * +*************************************************/ +const BlockCipher* Engine::block_cipher(const std::string& name) const + { + BlockCipher* retval = 0; + bc_map_lock->lock(); + std::map::const_iterator algo; + algo = bc_map.find(deref_alias(name)); + if(algo != bc_map.end()) + retval = algo->second; + bc_map_lock->unlock(); + if(!retval) + { + retval = find_block_cipher(deref_alias(name)); + add_algorithm(retval); + } + return retval; + } + +/************************************************* +* Acquire a StreamCipher * +*************************************************/ +const StreamCipher* Engine::stream_cipher(const std::string& name) const + { + StreamCipher* retval = 0; + sc_map_lock->lock(); + std::map::const_iterator algo; + algo = sc_map.find(deref_alias(name)); + if(algo != sc_map.end()) + retval = algo->second; + sc_map_lock->unlock(); + if(!retval) + { + retval = find_stream_cipher(deref_alias(name)); + add_algorithm(retval); + } + return retval; + } + +/************************************************* +* Acquire a HashFunction * +*************************************************/ +const HashFunction* Engine::hash(const std::string& name) const + { + HashFunction* retval = 0; + hf_map_lock->lock(); + std::map::const_iterator algo; + algo = hf_map.find(deref_alias(name)); + if(algo != hf_map.end()) + retval = algo->second; + hf_map_lock->unlock(); + if(!retval) + { + retval = find_hash(deref_alias(name)); + add_algorithm(retval); + } + return retval; + } + +/************************************************* +* Acquire a MessageAuthenticationCode * +*************************************************/ +const MessageAuthenticationCode* Engine::mac(const std::string& name) const + { + MessageAuthenticationCode* retval = 0; + mac_map_lock->lock(); + std::map::const_iterator algo; + algo = mac_map.find(deref_alias(name)); + if(algo != mac_map.end()) + retval = algo->second; + mac_map_lock->unlock(); + if(!retval) + { + retval = find_mac(deref_alias(name)); + add_algorithm(retval); + } + return retval; + } + +/************************************************* +* Add a block cipher to the lookup table * +*************************************************/ +void Engine::add_algorithm(BlockCipher* algo) const + { + if(!algo) return; + bc_map_lock->lock(); + if(bc_map.find(algo->name()) != bc_map.end()) + delete bc_map[algo->name()]; + bc_map[algo->name()] = algo; + bc_map_lock->unlock(); + } + +/************************************************* +* Add a stream cipher to the lookup table * +*************************************************/ +void Engine::add_algorithm(StreamCipher* algo) const + { + if(!algo) return; + sc_map_lock->lock(); + if(sc_map.find(algo->name()) != sc_map.end()) + delete sc_map[algo->name()]; + sc_map[algo->name()] = algo; + sc_map_lock->unlock(); + } + +/************************************************* +* Add a hash function to the lookup table * +*************************************************/ +void Engine::add_algorithm(HashFunction* algo) const + { + if(!algo) return; + hf_map_lock->lock(); + if(hf_map.find(algo->name()) != hf_map.end()) + delete hf_map[algo->name()]; + hf_map[algo->name()] = algo; + hf_map_lock->unlock(); + } + +/************************************************* +* Add a MAC to the lookup table * +*************************************************/ +void Engine::add_algorithm(MessageAuthenticationCode* algo) const + { + if(!algo) return; + mac_map_lock->lock(); + if(mac_map.find(algo->name()) != mac_map.end()) + delete mac_map[algo->name()]; + mac_map[algo->name()] = algo; + mac_map_lock->unlock(); + } + +/************************************************* +* Create an Engine * +*************************************************/ +Engine::Engine() + { + bc_map_lock = get_mutex(); + sc_map_lock = get_mutex(); + hf_map_lock = get_mutex(); + mac_map_lock = get_mutex(); + } + +/************************************************* +* Destroy an Engine * +*************************************************/ +Engine::~Engine() + { + std::map::iterator bc_iter; + for(bc_iter = bc_map.begin(); bc_iter != bc_map.end(); bc_iter++) + delete bc_iter->second; + + std::map::iterator sc_iter; + for(sc_iter = sc_map.begin(); sc_iter != sc_map.end(); sc_iter++) + delete sc_iter->second; + + std::map::iterator hf_iter; + for(hf_iter = hf_map.begin(); hf_iter != hf_map.end(); hf_iter++) + delete hf_iter->second; + + std::map::iterator mac_iter; + for(mac_iter = mac_map.begin(); mac_iter != mac_map.end(); mac_iter++) + delete mac_iter->second; + + delete bc_map_lock; + delete sc_map_lock; + delete hf_map_lock; + delete mac_map_lock; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +BlockCipher* Engine::find_block_cipher(const std::string&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +StreamCipher* Engine::find_stream_cipher(const std::string&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +HashFunction* Engine::find_hash(const std::string&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +MessageAuthenticationCode* Engine::find_mac(const std::string&) const + { + return 0; + } + +/************************************************* +* Basic No-Op Engine Implementation * +*************************************************/ +Keyed_Filter* Engine::get_cipher(const std::string&, Cipher_Dir) + { + return 0; + } + +} --- botan/engine.cpp +++ botan/engine.cpp @@ -0,0 +1,287 @@ +/************************************************* +* Engine Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::vector engines; + +} + +namespace Init { + +/************************************************* +* Initialize the list of Engines * +*************************************************/ +void startup_engines() + { + engines.push_back(new Default_Engine); + } + +/************************************************* +* Delete the list of Engines * +*************************************************/ +void shutdown_engines() + { + for(u32bit j = 0; j != engines.size(); j++) + delete engines[j]; + engines.clear(); + } + +} + +namespace Engine_Core { + +/************************************************* +* Add an Engine to the list * +*************************************************/ +void add_engine(Engine* engine) + { + engines.insert(engines.end() - 1, engine); + } + +/************************************************* +* Acquire an IF op * +*************************************************/ +IF_Operation* if_op(const BigInt& e, const BigInt& n, const BigInt& d, + const BigInt& p, const BigInt& q, const BigInt& d1, + const BigInt& d2, const BigInt& c) + { + for(u32bit j = 0; j != engines.size(); j++) + { + IF_Operation* op = engines[j]->if_op(e, n, d, p, q, d1, d2, c); + if(op) return op; + } + throw Lookup_Error("Engine_Core::if_op: Unable to find a working engine"); + } + +/************************************************* +* Acquire a DSA op * +*************************************************/ +DSA_Operation* dsa_op(const DL_Group& group, const BigInt& y, const BigInt& x) + { + for(u32bit j = 0; j != engines.size(); j++) + { + DSA_Operation* op = engines[j]->dsa_op(group, y, x); + if(op) return op; + } + throw Lookup_Error("Engine_Core::dsa_op: Unable to find a working engine"); + } + +/************************************************* +* Acquire a NR op * +*************************************************/ +NR_Operation* nr_op(const DL_Group& group, const BigInt& y, const BigInt& x) + { + for(u32bit j = 0; j != engines.size(); j++) + { + NR_Operation* op = engines[j]->nr_op(group, y, x); + if(op) return op; + } + throw Lookup_Error("Engine_Core::nr_op: Unable to find a working engine"); + } + +/************************************************* +* Acquire an ElGamal op * +*************************************************/ +ELG_Operation* elg_op(const DL_Group& group, const BigInt& y, const BigInt& x) + { + for(u32bit j = 0; j != engines.size(); j++) + { + ELG_Operation* op = engines[j]->elg_op(group, y, x); + if(op) return op; + } + throw Lookup_Error("Engine_Core::elg_op: Unable to find a working engine"); + } + +/************************************************* +* Acquire a DH op * +*************************************************/ +DH_Operation* dh_op(const DL_Group& group, const BigInt& x) + { + for(u32bit j = 0; j != engines.size(); j++) + { + DH_Operation* op = engines[j]->dh_op(group, x); + if(op) return op; + } + throw Lookup_Error("Engine_Core::dh_op: Unable to find a working engine"); + } + +} + +/************************************************* +* Acquire a modular reducer * +*************************************************/ +ModularReducer* get_reducer(const BigInt& n, bool convert_ok) + { + for(u32bit j = 0; j != engines.size(); j++) + { + ModularReducer* op = engines[j]->reducer(n, convert_ok); + if(op) return op; + } + throw Lookup_Error("get_reducer: Unable to find a working engine"); + } + +/************************************************* +* Acquire a block cipher * +*************************************************/ +const BlockCipher* retrieve_block_cipher(const std::string& name) + { + for(u32bit j = 0; j != engines.size(); j++) + { + const BlockCipher* algo = engines[j]->block_cipher(name); + if(algo) return algo; + } + return 0; + } + +/************************************************* +* Acquire a stream cipher * +*************************************************/ +const StreamCipher* retrieve_stream_cipher(const std::string& name) + { + for(u32bit j = 0; j != engines.size(); j++) + { + const StreamCipher* algo = engines[j]->stream_cipher(name); + if(algo) return algo; + } + return 0; + } + +/************************************************* +* Acquire a hash function * +*************************************************/ +const HashFunction* retrieve_hash(const std::string& name) + { + for(u32bit j = 0; j != engines.size(); j++) + { + const HashFunction* algo = engines[j]->hash(name); + if(algo) return algo; + } + return 0; + } + +/************************************************* +* Acquire an authentication code * +*************************************************/ +const MessageAuthenticationCode* retrieve_mac(const std::string& name) + { + for(u32bit j = 0; j != engines.size(); j++) + { + const MessageAuthenticationCode* algo = engines[j]->mac(name); + if(algo) return algo; + } + return 0; + } + +/************************************************* +* Add a new block cipher * +*************************************************/ +void add_algorithm(BlockCipher* algo) + { + for(u32bit j = 0; j != engines.size(); j++) + { + Default_Engine* engine = dynamic_cast(engines[j]); + if(engine) + { + engine->add_algorithm(algo); + return; + } + } + throw Invalid_State("add_algorithm: Couldn't find the Default_Engine"); + } + +/************************************************* +* Add a new stream cipher * +*************************************************/ +void add_algorithm(StreamCipher* algo) + { + for(u32bit j = 0; j != engines.size(); j++) + { + Default_Engine* engine = dynamic_cast(engines[j]); + if(engine) + { + engine->add_algorithm(algo); + return; + } + } + throw Invalid_State("add_algorithm: Couldn't find the Default_Engine"); + } + +/************************************************* +* Add a new hash function * +*************************************************/ +void add_algorithm(HashFunction* algo) + { + for(u32bit j = 0; j != engines.size(); j++) + { + Default_Engine* engine = dynamic_cast(engines[j]); + if(engine) + { + engine->add_algorithm(algo); + return; + } + } + throw Invalid_State("add_algorithm: Couldn't find the Default_Engine"); + } + +/************************************************* +* Add a new authentication code * +*************************************************/ +void add_algorithm(MessageAuthenticationCode* algo) + { + for(u32bit j = 0; j != engines.size(); j++) + { + Default_Engine* engine = dynamic_cast(engines[j]); + if(engine) + { + engine->add_algorithm(algo); + return; + } + } + throw Invalid_State("add_algorithm: Couldn't find the Default_Engine"); + } + +/************************************************* +* Get a cipher object * +*************************************************/ +Keyed_Filter* get_cipher(const std::string& algo_spec, Cipher_Dir direction) + { + for(u32bit j = 0; j != engines.size(); j++) + { + Keyed_Filter* algo = engines[j]->get_cipher(algo_spec, direction); + if(algo) 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); + 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); + } + +} --- botan/engine.h +++ botan/engine.h @@ -0,0 +1,91 @@ +/************************************************* +* Engine Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ENGINE_H__ +#define BOTAN_ENGINE_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Engine Base Class * +*************************************************/ +class Engine + { + public: + virtual IF_Operation* if_op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&) const; + virtual DSA_Operation* dsa_op(const DL_Group&, const BigInt&, + const BigInt&) const; + virtual NR_Operation* nr_op(const DL_Group&, const BigInt&, + const BigInt&) const; + virtual ELG_Operation* elg_op(const DL_Group&, const BigInt&, + const BigInt&) const; + virtual DH_Operation* dh_op(const DL_Group&, const BigInt&) const; + virtual ModularReducer* reducer(const BigInt&, bool) const; + + const BlockCipher* block_cipher(const std::string&) const; + const StreamCipher* stream_cipher(const std::string&) const; + const HashFunction* hash(const std::string&) const; + const MessageAuthenticationCode* mac(const std::string&) const; + + virtual Keyed_Filter* get_cipher(const std::string&, Cipher_Dir); + + void add_algorithm(BlockCipher*) const; + void add_algorithm(StreamCipher*) const; + void add_algorithm(HashFunction*) const; + void add_algorithm(MessageAuthenticationCode*) const; + + Engine(); + virtual ~Engine(); + private: + virtual BlockCipher* find_block_cipher(const std::string&) const; + virtual StreamCipher* find_stream_cipher(const std::string&) const; + virtual HashFunction* find_hash(const std::string&) const; + virtual MessageAuthenticationCode* find_mac(const std::string&) const; + + mutable std::map bc_map; + mutable std::map sc_map; + mutable std::map hf_map; + mutable std::map mac_map; + + Mutex* bc_map_lock; + Mutex* sc_map_lock; + Mutex* hf_map_lock; + Mutex* mac_map_lock; + }; + +namespace Engine_Core { + +/************************************************* +* Engine Management * +*************************************************/ +void add_engine(Engine*); + +/************************************************* +* Get an operation from an Engine * +*************************************************/ +IF_Operation* if_op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&); + +DSA_Operation* dsa_op(const DL_Group&, const BigInt&, const BigInt&); +NR_Operation* nr_op(const DL_Group&, const BigInt&, const BigInt&); + +ELG_Operation* elg_op(const DL_Group&, const BigInt&, const BigInt&); + +DH_Operation* dh_op(const DL_Group&, const BigInt&); + +} + +} + +#endif --- botan/enums.h +++ botan/enums.h @@ -0,0 +1,129 @@ +/************************************************* +* Enumerations Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ENUMS_H__ +#define BOTAN_ENUMS_H__ + +#include + +namespace Botan { + +/************************************************* +* ASN.1 Type and Class Tags * +*************************************************/ +enum ASN1_Tag { + 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, + + CONSTRUCTED = 0x20, + + UNIVERSAL = 0x00, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + PRIVATE = 0xC0, + + NO_OBJECT = 0xFF00, + DIRECTORY_STRING = 0xFF01 +}; + +/************************************************* +* 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 +}; + +/************************************************* +* 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 +}; + +/************************************************* +* X.509 Certificate Validation Result * +*************************************************/ +enum X509_Code { + VERIFIED, + UNKNOWN_X509_ERROR, + CANNOT_ESTABLISH_TRUST, + CERT_CHAIN_TOO_LONG, + SIGNATURE_ERROR, + POLICY_ERROR, + INVALID_USAGE, + + CERT_FORMAT_ERROR, + CERT_ISSUER_NOT_FOUND, + CERT_NOT_YET_VALID, + CERT_HAS_EXPIRED, + CERT_IS_REVOKED, + + CRL_FORMAT_ERROR, + CRL_ISSUER_NOT_FOUND, + CRL_NOT_YET_VALID, + CRL_HAS_EXPIRED, + + CA_CERT_CANNOT_SIGN, + CA_CERT_NOT_FOR_CERT_ISSUER, + CA_CERT_NOT_FOR_CRL_ISSUER +}; + +/************************************************* +* Various Other Enumerations * +*************************************************/ +enum RNG_Quality { Nonce = 0, PublicValue = 0, SessionKey, LongTermKey }; + +enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK }; + +enum X509_Encoding { RAW_BER, PEM }; + +enum Cipher_Dir { ENCRYPTION, DECRYPTION }; + +enum Signature_Format { IEEE_1363, DER_SEQUENCE }; + +} + +#endif --- botan/es_capi.cpp +++ botan/es_capi.cpp @@ -0,0 +1,96 @@ +/************************************************* +* Win32 CAPI EntropySource Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* CSP Handle * +*************************************************/ +class CSP_Handle + { + public: + CSP_Handle(u64bit); + ~CSP_Handle(); + + bool is_valid() const { return valid; } + + HCRYPTPROV get_handle() const { return handle; } + private: + HCRYPTPROV handle; + bool valid; + }; + +/************************************************* +* Initialize a CSP Handle * +*************************************************/ +CSP_Handle::CSP_Handle(u64bit capi_provider) + { + valid = false; + DWORD prov_type = (DWORD)capi_provider; + + if(CryptAcquireContext(&handle, 0, 0, prov_type, CRYPT_VERIFYCONTEXT)) + valid = true; + } + +/************************************************* +* Destroy a CSP Handle * +*************************************************/ +CSP_Handle::~CSP_Handle() + { + if(valid) + CryptReleaseContext(handle, 0); + } + +} + +/************************************************* +* Gather Entropy from Win32 CAPI * +*************************************************/ +u32bit Win32_CAPI_EntropySource::slow_poll(byte output[], u32bit length) + { + if(length > 64) + length = 64; + + for(u32bit j = 0; j != prov_types.size(); j++) + { + CSP_Handle csp(prov_types[j]); + if(!csp.is_valid()) continue; + if(CryptGenRandom(csp.get_handle(), length, output)) break; + } + return length; + } + +/************************************************* +* Gather Entropy from Win32 CAPI * +*************************************************/ +Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs) + { + std::vector capi_provs; + + if(provs == "") + capi_provs = Config::get_list("rng/ms_capi_prov_type"); + else + capi_provs = split_on(provs, ':'); + + for(u32bit j = 0; j != capi_provs.size(); j++) + { + if(capi_provs[j] == "RSA_FULL") prov_types.push_back(PROV_RSA_FULL); + if(capi_provs[j] == "INTEL_SEC") prov_types.push_back(PROV_INTEL_SEC); + if(capi_provs[j] == "FORTEZZA") prov_types.push_back(PROV_FORTEZZA); + if(capi_provs[j] == "RNG") prov_types.push_back(PROV_RNG); + } + + if(prov_types.size() == 0) + prov_types.push_back(PROV_RSA_FULL); + } + +} --- botan/es_capi.h +++ botan/es_capi.h @@ -0,0 +1,27 @@ +/************************************************* +* Win32 CAPI EntropySource Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EXT_ENTROPY_SRC_WIN32_CAPI_H__ +#define BOTAN_EXT_ENTROPY_SRC_WIN32_CAPI_H__ + +#include + +namespace Botan { + +/************************************************* +* Win32 CAPI Entropy Source * +*************************************************/ +class Win32_CAPI_EntropySource : public EntropySource + { + public: + u32bit slow_poll(byte[], u32bit); + Win32_CAPI_EntropySource(const std::string& = ""); + private: + std::vector prov_types; + }; + +} + +#endif --- botan/es_egd.cpp +++ botan/es_egd.cpp @@ -0,0 +1,88 @@ +/************************************************* +* EGD EntropySource Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef PF_LOCAL + #define PF_LOCAL PF_UNIX +#endif + +namespace Botan { + +/************************************************* +* EGD_EntropySource Constructor * +*************************************************/ +EGD_EntropySource::EGD_EntropySource(const std::string& egd_paths) + { + std::vector path_list = split_on(egd_paths, ':'); + std::vector defaults = Config::get_list("rng/egd_path"); + + for(u32bit j = 0; j != path_list.size(); j++) + paths.push_back(path_list[j]); + for(u32bit j = 0; j != defaults.size(); j++) + paths.push_back(defaults[j]); + } + +/************************************************* +* Gather Entropy from EGD * +*************************************************/ +u32bit EGD_EntropySource::do_poll(byte output[], u32bit length, + const std::string& path) const + { + if(length > 128) + length = 128; + + sockaddr_un addr; + std::memset(&addr, 0, sizeof(addr)); + addr.sun_family = PF_LOCAL; + + if(sizeof(addr.sun_path) < path.length() + 1) + throw Exception("EGD_EntropySource: Socket path is too long"); + std::strcpy(addr.sun_path, path.c_str()); + + int fd = socket(addr.sun_family, SOCK_STREAM, 0); + if(fd == -1) return 0; + + int len = sizeof(addr.sun_family) + std::strlen(addr.sun_path) + 1; + if(connect(fd, (struct sockaddr*)&addr, len)) + { close(fd); return 0; } + + byte buffer[2]; + buffer[0] = 1; + buffer[1] = (byte)length; + + if(write(fd, buffer, 2) != 2) { close(fd); return 0; } + if(read(fd, buffer, 1) != 1) { close(fd); return 0; } + + ssize_t count = read(fd, output, buffer[0]); + + if(count == -1) { close(fd); return 0; } + + close(fd); + + return count; + } + +/************************************************* +* Gather Entropy from EGD * +*************************************************/ +u32bit EGD_EntropySource::slow_poll(byte output[], u32bit length) + { + for(u32bit j = 0; j != paths.size(); j++) + { + u32bit got = do_poll(output, length, paths[j]); + if(got) + return got; + } + return 0; + } + +} --- botan/es_egd.h +++ botan/es_egd.h @@ -0,0 +1,30 @@ +/************************************************* +* EGD EntropySource Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EXT_ENTROPY_SRC_EGD_H__ +#define BOTAN_EXT_ENTROPY_SRC_EGD_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* EGD Entropy Source * +*************************************************/ +class EGD_EntropySource : public EntropySource + { + public: + u32bit slow_poll(byte[], u32bit); + EGD_EntropySource(const std::string& = ""); + private: + u32bit do_poll(byte[], u32bit, const std::string&) const; + std::vector paths; + }; + +} + +#endif --- botan/es_file.cpp +++ botan/es_file.cpp @@ -0,0 +1,53 @@ +/************************************************* +* File EntropySource Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* File_EntropySource Constructor * +*************************************************/ +File_EntropySource::File_EntropySource(const std::string& sources) + { + std::vector source_list = split_on(sources, ':'); + std::vector defaults = Config::get_list("rng/es_files"); + + for(u32bit j = 0; j != source_list.size(); j++) + add_source(source_list[j]); + for(u32bit j = 0; j != defaults.size(); j++) + add_source(defaults[j]); + } + +/************************************************* +* Add another file to the list * +*************************************************/ +void File_EntropySource::add_source(const std::string& source) + { + sources.push_back(source); + } + +/************************************************* +* Gather Entropy from Randomness Source * +*************************************************/ +u32bit File_EntropySource::slow_poll(byte output[], u32bit length) + { + u32bit read = 0; + for(u32bit j = 0; j != sources.size(); j++) + { + std::ifstream random_source(sources[j].c_str()); + if(!random_source) continue; + random_source.read((char*)output + read, length); + read += random_source.gcount(); + length -= random_source.gcount(); + if(length == 0) + break; + } + return read; + } + +} --- botan/es_file.h +++ botan/es_file.h @@ -0,0 +1,30 @@ +/************************************************* +* File EntropySource Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ENTROPY_SRC_FILE_H__ +#define BOTAN_ENTROPY_SRC_FILE_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* File Based Entropy Source * +*************************************************/ +class File_EntropySource : public EntropySource + { + public: + u32bit slow_poll(byte[], u32bit); + void add_source(const std::string&); + File_EntropySource(const std::string& = ""); + private: + std::vector sources; + }; + +} + +#endif --- botan/exceptn.cpp +++ botan/exceptn.cpp @@ -0,0 +1,70 @@ +/************************************************* +* Exceptions Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Constructor for Invalid_Key_Length * +*************************************************/ +Invalid_Key_Length::Invalid_Key_Length(const std::string& name, u32bit length) + { + set_msg(name + " cannot accept a key of length " + to_string(length)); + } + +/************************************************* +* Constructor for Invalid_Block_Size * +*************************************************/ +Invalid_Block_Size::Invalid_Block_Size(const std::string& mode, + const std::string& pad) + { + set_msg("Padding method " + pad + " cannot be used with " + mode); + } + +/************************************************* +* Constructor for Invalid_IV_Length * +*************************************************/ +Invalid_IV_Length::Invalid_IV_Length(const std::string& mode, u32bit bad_len) + { + set_msg("IV length " + to_string(bad_len) + " is invalid for " + mode); + } + +/************************************************* +* Constructor for Invalid_Message_Number * +*************************************************/ +Invalid_Message_Number::Invalid_Message_Number(const std::string& where, + u32bit message_no) + { + set_msg("Pipe::" + where + ": Invalid message number " + + to_string(message_no)); + } + +/************************************************* +* Constructor for Algorithm_Not_Found * +*************************************************/ +Algorithm_Not_Found::Algorithm_Not_Found(const std::string& name) + { + set_msg("Could not find any algorithm named \"" + name + "\""); + } + +/************************************************* +* Constructor for Invalid_Algorithm_Name * +*************************************************/ +Invalid_Algorithm_Name::Invalid_Algorithm_Name(const std::string& name) + { + set_msg("Invalid algorithm name: " + name); + } + +/************************************************* +* Constructor for Config_Error * +*************************************************/ +Config_Error::Config_Error(const std::string& err, u32bit line) + { + set_msg("Config error at line " + to_string(line) + ": " + err); + } + +} --- botan/exceptn.h +++ botan/exceptn.h @@ -0,0 +1,203 @@ +/************************************************* +* Exceptions Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EXCEPTION_H__ +#define BOTAN_EXCEPTION_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Exception Base Class * +*************************************************/ +class Exception : public std::exception + { + public: + const char* what() const throw() { return msg.c_str(); } + Exception(const std::string& m = "Unknown error") { set_msg(m); } + virtual ~Exception() throw() {} + protected: + void set_msg(const std::string& m) { msg = "Botan: " + m; } + private: + std::string msg; + }; + +/************************************************* +* Invalid_Argument Exception * +*************************************************/ +struct Invalid_Argument : public Exception + { + Invalid_Argument(const std::string& err = "") : Exception(err) {} + }; + +/************************************************* +* Invalid_Key_Length Exception * +*************************************************/ +struct Invalid_Key_Length : public Invalid_Argument + { + Invalid_Key_Length(const std::string&, u32bit); + }; + +/************************************************* +* Invalid_Block_Size Exception * +*************************************************/ +struct Invalid_Block_Size : public Invalid_Argument + { + Invalid_Block_Size(const std::string&, const std::string&); + }; + +/************************************************* +* Invalid_IV_Length Exception * +*************************************************/ +struct Invalid_IV_Length : public Invalid_Argument + { + Invalid_IV_Length(const std::string&, u32bit); + }; + +/************************************************* +* Invalid_Message_Number Exception * +*************************************************/ +struct Invalid_Message_Number : public Invalid_Argument + { + Invalid_Message_Number(const std::string&, u32bit); + }; + +/************************************************* +* Invalid_State Exception * +*************************************************/ +struct Invalid_State : public Exception + { + Invalid_State(const std::string& err) : Exception(err) {} + }; + +/************************************************* +* PRNG_Unseeded Exception * +*************************************************/ +struct PRNG_Unseeded : public Invalid_State + { + PRNG_Unseeded(const std::string& algo) : + Invalid_State("PRNG not seeded: " + algo) {} + }; + +/************************************************* +* Policy_Violation Exception * +*************************************************/ +struct Policy_Violation : public Invalid_State + { + Policy_Violation(const std::string& err) : + Invalid_State("Policy violation: " + err) {} + }; + +/************************************************* +* Lookup_Error Exception * +*************************************************/ +struct Lookup_Error : public Exception + { + Lookup_Error(const std::string& err) : Exception(err) {} + }; + +/************************************************* +* Algorithm_Not_Found Exception * +*************************************************/ +struct Algorithm_Not_Found : public Exception + { + Algorithm_Not_Found(const std::string&); + }; + +/************************************************* +* Format_Error Exception * +*************************************************/ +struct Format_Error : public Exception + { + Format_Error(const std::string& err = "") : Exception(err) {} + }; + +/************************************************* +* Invalid_Algorithm_Name Exception * +*************************************************/ +struct Invalid_Algorithm_Name : public Format_Error + { + Invalid_Algorithm_Name(const std::string&); + }; + +/************************************************* +* Encoding_Error Exception * +*************************************************/ +struct Encoding_Error : public Format_Error + { + Encoding_Error(const std::string& name) : + Format_Error("Encoding error: " + name) {} + }; + +/************************************************* +* Decoding_Error Exception * +*************************************************/ +struct Decoding_Error : public Format_Error + { + Decoding_Error(const std::string& name) : + Format_Error("Decoding error: " + name) {} + }; + +/************************************************* +* Invalid_OID Exception * +*************************************************/ +struct Invalid_OID : public Decoding_Error + { + Invalid_OID(const std::string& oid) : + Decoding_Error("Invalid ASN.1 OID: " + oid) {} + }; + +/************************************************* +* Stream_IO_Error Exception * +*************************************************/ +struct Stream_IO_Error : public Exception + { + Stream_IO_Error(const std::string& err) : + Exception("I/O error: " + err) {} + }; + +/************************************************* +* Configuration Error Exception * +*************************************************/ +struct Config_Error : public Format_Error + { + Config_Error(const std::string& err) : + Format_Error("Config error: " + err) {} + Config_Error(const std::string&, u32bit); + }; + +/************************************************* +* Integrity Failure Exception * +*************************************************/ +struct Integrity_Failure : public Exception + { + Integrity_Failure(const std::string& err) : + Exception("Integrity failure: " + err) {} + }; + +/************************************************* +* Internal_Error Exception * +*************************************************/ +struct Internal_Error : public Exception + { + Internal_Error(const std::string& err) : + Exception("Internal error: " + err) {} + }; + +/************************************************* +* Self Test Failure Exception * +*************************************************/ +struct Self_Test_Failure : public Internal_Error + { + Self_Test_Failure(const std::string& err) : + Internal_Error("Self test failed: " + err) {} + }; + +} + +#endif --- botan/filter.cpp +++ botan/filter.cpp @@ -0,0 +1,117 @@ +/************************************************* +* Filter Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Filter Constructor * +*************************************************/ +Filter::Filter(u32bit count) + { + set_port_count(count); + } + +/************************************************* +* Set/Reset next * +*************************************************/ +void Filter::set_port_count(u32bit n) + { + next.clear(); + next.resize(n); + port_num = 0; + filter_owns = 0; + } + +/************************************************* +* Send data to all ports * +*************************************************/ +void Filter::send(const byte input[], u32bit length) + { + UI::pulse(UI::PIPE_WRITE); + + bool nothing_attached = true; + for(u32bit j = 0; j != total_ports(); j++) + if(next[j]) + { + if(write_queue.has_items()) + next[j]->write(write_queue, write_queue.size()); + next[j]->write(input, length); + nothing_attached = false; + } + if(nothing_attached) + write_queue.append(input, length); + else if(write_queue.has_items()) + write_queue.destroy(); + } + +/************************************************* +* Start a new message * +*************************************************/ +void Filter::new_msg() + { + start_msg(); + for(u32bit j = 0; j != total_ports(); j++) + if(next[j]) + next[j]->new_msg(); + } + +/************************************************* +* End the current message * +*************************************************/ +void Filter::finish_msg() + { + end_msg(); + for(u32bit 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(u32bit 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 0; + } + +/************************************************* +* Return the total number of ports * +*************************************************/ +u32bit Filter::total_ports() const + { + return next.size(); + } + +} --- botan/filter.h +++ botan/filter.h @@ -0,0 +1,53 @@ +/************************************************* +* Filter Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_FILTER_H__ +#define BOTAN_FILTER_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Filter Base Class * +*************************************************/ +class Filter + { + public: + virtual void write(const byte[], u32bit) = 0; + virtual void start_msg() {} + virtual void end_msg() {} + virtual bool attachable() { return true; } + void new_msg(); + void finish_msg(); + virtual ~Filter() {} + protected: + virtual void send(const byte[], u32bit); + void send(byte input) { send(&input, 1); } + void send(const MemoryRegion& in) { send(in.begin(), in.size()); } + + void attach(Filter*); + u32bit total_ports() const; + u32bit current_port() const { return port_num; } + void set_port_count(u32bit); + void set_port(u32bit); + u32bit owns() const { return filter_owns; } + void incr_owns() { filter_owns++; } + Filter(u32bit = 1); + private: + friend class Pipe; + friend class Fork; + Filter(const Filter&) {} + Filter& operator=(const Filter&) { return (*this); } + Filter* get_next() const; + SecureVector write_queue; + std::vector next; + u32bit port_num, filter_owns; + }; + +} + +#endif --- botan/filters.cpp +++ botan/filters.cpp @@ -0,0 +1,95 @@ +/************************************************* +* Filters Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* StreamCipher_Filter Constructor * +*************************************************/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : + buffer(DEFAULT_BUFFERSIZE) + { + base_ptr = cipher = get_stream_cipher(sc_name); + } + +/************************************************* +* Set the IV of a stream cipher * +*************************************************/ +void StreamCipher_Filter::set_iv(const InitializationVector& iv) + { + cipher->resync(iv.begin(), iv.length()); + } + +/************************************************* +* Write data into a StreamCipher_Filter * +*************************************************/ +void StreamCipher_Filter::write(const byte input[], u32bit length) + { + while(length) + { + u32bit copied = std::min(length, buffer.size()); + cipher->encrypt(input, buffer, copied); + send(buffer, copied); + input += copied; + length -= copied; + } + } + +/************************************************* +* Hash_Filter Constructor * +*************************************************/ +Hash_Filter::Hash_Filter(const std::string& hash_name, u32bit len) : + OUTPUT_LENGTH(len) + { + hash = get_hash(hash_name); + } + +/************************************************* +* Complete a calculation by a Hash_Filter * +*************************************************/ +void Hash_Filter::end_msg() + { + SecureVector 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, u32bit len) : + OUTPUT_LENGTH(len) + { + base_ptr = mac = get_mac(mac_name); + } + +/************************************************* +* MAC_Filter Constructor * +*************************************************/ +MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, + u32bit len) : OUTPUT_LENGTH(len) + { + base_ptr = mac = get_mac(mac_name); + mac->set_key(key); + } + +/************************************************* +* Complete a calculation by a MAC_Filter * +*************************************************/ +void MAC_Filter::end_msg() + { + SecureVector output = mac->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +} --- botan/filters.h +++ botan/filters.h @@ -0,0 +1,72 @@ +/************************************************* +* Filters Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_FILTERS_H__ +#define BOTAN_FILTERS_H__ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Stream Cipher Filter * +*************************************************/ +class StreamCipher_Filter : public Keyed_Filter + { + public: + void seek(u32bit position) { cipher->seek(position); } + bool supports_resync() const { return (cipher->IV_LENGTH != 0); } + + void set_iv(const InitializationVector&); + void write(const byte[], u32bit); + + StreamCipher_Filter(const std::string&); + ~StreamCipher_Filter() { delete cipher; } + private: + SecureVector buffer; + StreamCipher* cipher; + }; + +/************************************************* +* Hash Filter * +*************************************************/ +class Hash_Filter : public Filter + { + public: + void write(const byte input[], u32bit len) { hash->update(input, len); } + void end_msg(); + + Hash_Filter(const std::string&, u32bit = 0); + ~Hash_Filter() { delete hash; } + private: + const u32bit OUTPUT_LENGTH; + HashFunction* hash; + }; + +/************************************************* +* MessageAuthenticationCode Filter * +*************************************************/ +class MAC_Filter : public Keyed_Filter + { + public: + void write(const byte input[], u32bit len) { mac->update(input, len); } + void end_msg(); + + MAC_Filter(const std::string&, u32bit = 0); + MAC_Filter(const std::string&, const SymmetricKey&, u32bit = 0); + ~MAC_Filter() { delete mac; } + private: + const u32bit OUTPUT_LENGTH; + MessageAuthenticationCode* mac; + }; + +} + +#endif --- botan/fips140.cpp +++ botan/fips140.cpp @@ -0,0 +1,178 @@ +/************************************************* +* FIPS-140 Self Tests Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace FIPS140 { + +namespace { + +/************************************************* +* Perform a Known Answer Test * +*************************************************/ +void do_kat(const std::string& in, const std::string& out, + const std::string& algo_name, Filter* filter) + { + if(out.length()) + { + Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder); + pipe.process_msg(in); + + if(out != pipe.read_all_as_string()) + throw Self_Test_Failure("FIPS-140 " + algo_name + " test"); + } + } + +/************************************************* +* Perform a KAT for a cipher * +*************************************************/ +void cipher_kat(const std::string& in, const std::string& out, + const std::string& key, const std::string& iv, + const std::string& cipher) + { + do_kat(in, out, cipher, get_cipher(cipher, key, iv, ENCRYPTION)); + do_kat(out, in, cipher, get_cipher(cipher, key, iv, DECRYPTION)); + } + +/************************************************* +* Perform a KAT for a cipher * +*************************************************/ +void cipher_kat(const std::string& cipher, const std::string& key, + const std::string& iv, 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) + { + if(!have_block_cipher(cipher)) + return; + + cipher_kat(in, ecb_out, key, "", cipher + "/ECB"); + cipher_kat(in, cbc_out, key, iv, cipher + "/CBC/NoPadding"); + cipher_kat(in, cfb_out, key, iv, cipher + "/CFB"); + cipher_kat(in, ofb_out, key, iv, cipher + "/OFB"); + cipher_kat(in, ctr_out, key, iv, cipher + "/CTR-BE"); + } + +/************************************************* +* Perform a KAT for a hash * +*************************************************/ +void hash_kat(const std::string& hash, const std::string& in, + const std::string& out) + { + if(!have_hash(hash)) + return; + do_kat(in, out, hash, new Hash_Filter(hash)); + } + +/************************************************* +* Perform a KAT for a MAC * +*************************************************/ +void mac_kat(const std::string& mac, const std::string& in, + const std::string& out, const std::string& key) + { + if(!have_mac(mac)) + return; + do_kat(in, out, mac, new MAC_Filter(mac, key)); + } + +} + +/************************************************* +* Perform FIPS 140 Self Tests * +*************************************************/ +bool passes_self_tests() + { + try { + cipher_kat("DES", "0123456789ABCDEF", "1234567890ABCDEF", + "4E6F77206973207468652074696D6520666F7220616C6C20", + "3FA40E8A984D48156A271787AB8883F9893D51EC4B563B53", + "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6", + "F3096249C7F46E51A69E839B1A92F78403467133898EA622", + "F3096249C7F46E5135F24A242EEB3D3F3D6D5BE3255AF8C3", + "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75"); + + cipher_kat("TripleDES", + "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E", + "C141B5FCCD28DC8A", + "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68", + "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4", + "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9", + "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B", + "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62", + "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371"); + + cipher_kat("Skipjack", "1555E5531C3A169B2D65", "6EC9795701F49864", + "00AFA48E9621E52E8CBDA312660184EDDB1F33D9DACDA8DA", + "DBEC73562EFCAEB56204EB8AE9557EBF77473FBB52D17CD1", + "0C7B0B74E21F99B8F2C8DF37879F6C044967F42A796DCA8B", + "79FDDA9724E36CC2E023E9A5C717A8A8A7FDA465CADCBF63", + "79FDDA9724E36CC26CACBD83C1ABC06EAF5B249BE5B1E040", + "79FDDA9724E36CC211B0AEC607B95A96BCDA318440B82F49"); + + cipher_kat("AES", + "2B7E151628AED2A6ABF7158809CF4F3C", + "000102030405060708090A0B0C0D0E0F", + "6BC1BEE22E409F96E93D7E117393172A" + "AE2D8A571E03AC9C9EB76FAC45AF8E51", + "3AD77BB40D7A3660A89ECAF32466EF97" + "F5D3D58503B9699DE785895A96FDBAAF", + "7649ABAC8119B246CEE98E9B12E9197D" + "5086CB9B507219EE95DB113A917678B2", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "C8A64537A0B3A93FCDE3CDAD9F1CE58B", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "7789508D16918F03F53C52DAC54ED825", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "010C041999E03F36448624483E582D0E"); + + hash_kat("SHA-1", "", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"); + hash_kat("SHA-1", "616263", "A9993E364706816ABA3E25717850C26C9CD0D89D"); + hash_kat("SHA-1", + "6162636462636465636465666465666765666768666768696768696A" + "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071", + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"); + + mac_kat("HMAC(SHA-1)", "4869205468657265", + "B617318655057264E28BC0B6FB378C8EF146BE00", + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"); + + mac_kat("X9.19-MAC", + "31311C3931383237333634351C1C35383134333237361C1C3B3132333435" + "36373839303132333435363D3939313231303030303F1C30303031323530" + "301C393738363533343132343837363932331C", "C209CCB78EE1B606", + "0123456789ABCDEFFEDCBA9876543210"); + } + catch(std::exception) + { + return false; + } + + return true; + } + +/************************************************* +* Check a SHA-1 EDC * +*************************************************/ +bool good_edc(const std::string& filename, const std::string& edc) + { + if(filename == "" || edc == "") + return false; + + Pipe pipe1(new Hash_Filter("SHA-1")); + Pipe pipe2(new Hex_Decoder); + + DataSource_Stream in(filename); + pipe1.process_msg(in); + pipe2.process_msg(edc); + + return (pipe1.read_all() == pipe2.read_all()); + } + +} + +} --- botan/fips140.h +++ botan/fips140.h @@ -0,0 +1,25 @@ +/************************************************* +* FIPS 140 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_FIPS140_H__ +#define BOTAN_FIPS140_H__ + +#include + +namespace Botan { + +namespace FIPS140 { + +/************************************************* +* FIPS 140-2 Self Tests * +*************************************************/ +bool passes_self_tests(); +bool good_edc(const std::string&, const std::string&); + +} + +} + +#endif --- botan/fips_rng.cpp +++ botan/fips_rng.cpp @@ -0,0 +1,147 @@ +/************************************************* +* FIPS 186-2 RNG Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Generate a buffer of random bytes * +*************************************************/ +void FIPS_186_RNG::randomize(byte out[], u32bit length) throw(PRNG_Unseeded) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + xkey = gen_xval(); + while(length) + { + const u32bit copied = std::min(length, buffer.size() - position); + copy_mem(out, buffer + position, copied); + out += copied; + length -= copied; + update_buffer(); + } + } + +/************************************************* +* Compute the next buffer * +*************************************************/ +void FIPS_186_RNG::update_buffer() throw() + { + SecureVector xval = gen_xval(); + do_add(xval, xkey); + + buffer = do_hash(xval); + + for(u32bit j = xkey.size(); j > 0; j--) + if(++xkey[j-1]) + break; + + do_add(xkey, buffer); + } + +/************************************************* +* Add entropy to internal state * +*************************************************/ +void FIPS_186_RNG::add_randomness(const byte data[], u32bit length) throw() + { + randpool->add_entropy(data, length); + if(is_seeded()) + xkey = gen_xval(); + } + +/************************************************* +* Check if the the PRNG is seeded * +*************************************************/ +bool FIPS_186_RNG::is_seeded() const + { + return randpool->is_seeded(); + } + +/************************************************* +* Add x to y, modulo 2**160 * +*************************************************/ +void FIPS_186_RNG::do_add(MemoryRegion& x, const MemoryRegion& y) + { + if(x.size() != y.size()) + throw Invalid_Argument("FIPS_186_RNG::do_add: x and y are unequal size"); + + byte carry = 0; + for(u32bit j = x.size(); j > 0; j--) + { + u16bit sum = (u16bit)x[j-1] + y[j-1] + carry; + carry = get_byte(0, sum); + x[j-1] = get_byte(1, sum); + } + } + +/************************************************* +* Generate the XKEY/XSEED parameter * +*************************************************/ +SecureVector FIPS_186_RNG::gen_xval() + { + SecureVector xval(20); + randpool->randomize(xval, xval.size()); + return xval; + } + +/************************************************* +* Calculate the FIPS-186 G function * +*************************************************/ +SecureVector FIPS_186_RNG::do_hash(const MemoryRegion& xval) + { + SecureVector M(64), output(20); + M.copy(xval, xval.size()); + + sha1.clear(); + sha1.hash(M); + for(u32bit j = 0; j != 20; j++) + output[j] = get_byte(j % 4, sha1.digest[j/4]); + sha1.clear(); + + return output; + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void FIPS_186_RNG::clear() throw() + { + sha1.clear(); + xkey.clear(); + buffer.clear(); + entropy = position = 0; + } + +/************************************************* +* Return the name of this type * +*************************************************/ +std::string FIPS_186_RNG::name() const + { + return "FIPS-186"; + } + +/************************************************* +* FIPS 186-2 RNG Constructor * +*************************************************/ +FIPS_186_RNG::FIPS_186_RNG() + { + xkey.create(sha1.OUTPUT_LENGTH); + buffer.create(sha1.OUTPUT_LENGTH); + randpool = new Randpool; + entropy = position = 0; + } + +/************************************************* +* FIPS 186-2 RNG Destructor * +*************************************************/ +FIPS_186_RNG::~FIPS_186_RNG() + { + delete randpool; + } + +} --- botan/fips_rng.h +++ botan/fips_rng.h @@ -0,0 +1,41 @@ +/************************************************* +* FIPS 186-2 RNG Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_FIPS_186_RNG_H__ +#define BOTAN_FIPS_186_RNG_H__ + +#include + +namespace Botan { + +/************************************************* +* FIPS 186-2 RNG * +*************************************************/ +class FIPS_186_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], u32bit) throw(PRNG_Unseeded); + bool is_seeded() const; + void clear() throw(); + std::string name() const; + + FIPS_186_RNG(); + ~FIPS_186_RNG(); + private: + void add_randomness(const byte[], u32bit) throw(); + void update_buffer() throw(); + void do_add(MemoryRegion&, const MemoryRegion&); + SecureVector gen_xval(); + SecureVector do_hash(const MemoryRegion&); + + SHA_160 sha1; + SecureVector xkey, buffer; + RandomNumberGenerator* randpool; + u32bit position; + }; + +} + +#endif --- botan/fused.cpp +++ botan/fused.cpp @@ -0,0 +1,66 @@ +/************************************************* +* Fused Arithmetic Operations Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Fused 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 u32bit a_sw = a.sig_words(); + const u32bit b_sw = b.sig_words(); + const u32bit c_sw = c.sig_words(); + + BigInt r(sign, std::max(a.size() + b.size(), c_sw) + 1); + bigint_mul3(r.get_reg(), r.size(), + a.data(), a.size(), a_sw, + b.data(), b.size(), b_sw); + const u32bit r_size = std::max(r.sig_words(), c_sw); + bigint_add2(r.get_reg(), r_size, c.data(), c_sw); + return r; + } + +/************************************************* +* Fused 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; + } + +/************************************************* +* Fused Multiply/Modulo Operation * +*************************************************/ +BigInt mul_mod(const BigInt& a, const BigInt& b, const BigInt& m) + { + if(a.is_negative() || b.is_negative()) + throw Invalid_Argument("mul_mod: First two arguments must be >= 0"); + if(m <= 0) + throw Invalid_Argument("mul_mod: Modulo must be positive"); + + BigInt r = a; + r *= b; + r %= m; + return r; + } + +} --- botan/get_algo.cpp +++ botan/get_algo.cpp @@ -0,0 +1,239 @@ +/************************************************* +* Algorithm Retrieval Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Get a block cipher by name * +*************************************************/ +BlockCipher* get_block_cipher(const std::string& name) + { + const BlockCipher* cipher = retrieve_block_cipher(name); + if(cipher) + return cipher->clone(); + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Get a stream cipher by name * +*************************************************/ +StreamCipher* get_stream_cipher(const std::string& name) + { + const StreamCipher* cipher = retrieve_stream_cipher(name); + if(cipher) + return cipher->clone(); + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Get a hash function by name * +*************************************************/ +HashFunction* get_hash(const std::string& name) + { + const HashFunction* hash = retrieve_hash(name); + if(hash) + return hash->clone(); + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Get a MAC by name * +*************************************************/ +MessageAuthenticationCode* get_mac(const std::string& name) + { + const MessageAuthenticationCode* mac = retrieve_mac(name); + if(mac) + return mac->clone(); + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Get a S2K algorithm by name * +*************************************************/ +S2K* get_s2k(const std::string& name) + { + const S2K* s2k = retrieve_s2k(name); + if(s2k) + return s2k->clone(); + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Get a block cipher padding method by name * +*************************************************/ +const BlockCipherModePaddingMethod* get_bc_pad(const std::string& name) + { + const BlockCipherModePaddingMethod* pad = retrieve_bc_pad(name); + if(pad) + return pad; + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Query if an algorithm exists * +*************************************************/ +bool have_algorithm(const std::string& name) + { + if(retrieve_block_cipher(name)) + return true; + if(retrieve_stream_cipher(name)) + return true; + if(retrieve_hash(name)) + return true; + if(retrieve_mac(name)) + return true; + return false; + } + +/************************************************* +* Query if Botan has the named block cipher * +*************************************************/ +bool have_block_cipher(const std::string& name) + { + if(retrieve_block_cipher(name)) + return true; + return false; + } + +/************************************************* +* Query if Botan has the named stream cipher * +*************************************************/ +bool have_stream_cipher(const std::string& name) + { + if(retrieve_stream_cipher(name)) + return true; + return false; + } + +/************************************************* +* Query if Botan has the named hash function * +*************************************************/ +bool have_hash(const std::string& name) + { + if(retrieve_hash(name)) + return true; + return false; + } + +/************************************************* +* Query if Botan has the named MAC * +*************************************************/ +bool have_mac(const std::string& name) + { + if(retrieve_mac(name)) + return true; + return false; + } + +/************************************************* +* Query the BLOCK_SIZE of a block cipher * +*************************************************/ +u32bit block_size_of(const std::string& name) + { + const BlockCipher* cipher = retrieve_block_cipher(name); + if(cipher) + return cipher->BLOCK_SIZE; + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Query the OUTPUT_LENGTH of a hash or MAC * +*************************************************/ +u32bit output_length_of(const std::string& name) + { + const HashFunction* hash = retrieve_hash(name); + if(hash) + return hash->OUTPUT_LENGTH; + + const MessageAuthenticationCode* mac = retrieve_mac(name); + if(mac) + return mac->OUTPUT_LENGTH; + + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Check if a keylength is valid for this algo * +*************************************************/ +bool valid_keylength_for(u32bit key_len, const std::string& name) + { + const BlockCipher* bc = retrieve_block_cipher(name); + if(bc) + return bc->valid_keylength(key_len); + + const StreamCipher* sc = retrieve_stream_cipher(name); + if(sc) + return sc->valid_keylength(key_len); + + const MessageAuthenticationCode* mac = retrieve_mac(name); + if(mac) + return mac->valid_keylength(key_len); + + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Query the MINIMUM_KEYLENGTH of an algorithm * +*************************************************/ +u32bit min_keylength_of(const std::string& name) + { + const BlockCipher* bc = retrieve_block_cipher(name); + if(bc) + return bc->MINIMUM_KEYLENGTH; + + const StreamCipher* sc = retrieve_stream_cipher(name); + if(sc) + return sc->MINIMUM_KEYLENGTH; + + const MessageAuthenticationCode* mac = retrieve_mac(name); + if(mac) + return mac->MINIMUM_KEYLENGTH; + + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Query the MAXIMUM_KEYLENGTH of an algorithm * +*************************************************/ +u32bit max_keylength_of(const std::string& name) + { + const BlockCipher* bc = retrieve_block_cipher(name); + if(bc) + return bc->MAXIMUM_KEYLENGTH; + + const StreamCipher* sc = retrieve_stream_cipher(name); + if(sc) + return sc->MAXIMUM_KEYLENGTH; + + const MessageAuthenticationCode* mac = retrieve_mac(name); + if(mac) + return mac->MAXIMUM_KEYLENGTH; + + throw Algorithm_Not_Found(name); + } + +/************************************************* +* Query the KEYLENGTH_MULTIPLE of an algorithm * +*************************************************/ +u32bit keylength_multiple_of(const std::string& name) + { + const BlockCipher* bc = retrieve_block_cipher(name); + if(bc) + return bc->KEYLENGTH_MULTIPLE; + + const StreamCipher* sc = retrieve_stream_cipher(name); + if(sc) + return sc->KEYLENGTH_MULTIPLE; + + const MessageAuthenticationCode* mac = retrieve_mac(name); + if(mac) + return mac->KEYLENGTH_MULTIPLE; + + throw Algorithm_Not_Found(name); + } + +} --- botan/get_enc.cpp +++ botan/get_enc.cpp @@ -0,0 +1,141 @@ +/************************************************* +* EMSA/EME/KDF/MGF Retrieval Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Get an EMSA by name * +*************************************************/ +EMSA* get_emsa(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + const std::string emsa_name = deref_alias(name[0]); + + if(emsa_name == "Raw") + { + if(name.size() == 1) + return new EMSA_Raw; + } + else if(emsa_name == "EMSA1") + { + if(name.size() == 2) + return new EMSA1(name[1]); + } + else if(emsa_name == "EMSA2") + { + if(name.size() == 2) + return new EMSA2(name[1]); + } + else if(emsa_name == "EMSA3") + { + if(name.size() == 2) + return new EMSA3(name[1]); + } + else if(emsa_name == "EMSA4") + { + if(name.size() == 2) + return new EMSA4(name[1], "MGF1"); + if(name.size() == 3) + return new EMSA4(name[1], name[2]); + if(name.size() == 4) + return new EMSA4(name[1], name[2], to_u32bit(name[3])); + } + else + throw Algorithm_Not_Found(algo_spec); + + throw Invalid_Algorithm_Name(algo_spec); + } + +/************************************************* +* Get an EME by name * +*************************************************/ +EME* get_eme(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + const std::string eme_name = deref_alias(name[0]); + + if(eme_name == "PKCS1v15") + { + if(name.size() == 1) + return new EME_PKCS1v15; + } + else if(eme_name == "EME1") + { + if(name.size() == 2) + return new EME1(name[1], "MGF1"); + if(name.size() == 3) + return new EME1(name[1], name[2]); + } + else + throw Algorithm_Not_Found(algo_spec); + + throw Invalid_Algorithm_Name(algo_spec); + } + +/************************************************* +* Get an KDF by name * +*************************************************/ +KDF* get_kdf(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + const std::string kdf_name = deref_alias(name[0]); + + if(kdf_name == "TLS-PRF") + { + if(name.size() == 1) + return new TLS_PRF; + } + else if(kdf_name == "SSL3-PRF") + { + if(name.size() == 1) + return new SSL3_PRF; + } + else if(kdf_name == "X9.42-PRF") + { + if(name.size() == 2) + return new X942_PRF(name[1]); + } + else if(kdf_name == "KDF1") + { + if(name.size() == 2) + return new KDF1(name[1]); + } + else if(kdf_name == "KDF2") + { + if(name.size() == 2) + return new KDF2(name[1]); + } + else + throw Algorithm_Not_Found(algo_spec); + + throw Invalid_Algorithm_Name(algo_spec); + } + +/************************************************* +* Get a MGF by name * +*************************************************/ +MGF* get_mgf(const std::string& algo_spec) + { + std::vector name = parse_algorithm_name(algo_spec); + const std::string mgf_name = deref_alias(name[0]); + + if(mgf_name == "MGF1") + { + if(name.size() == 2) + return new MGF1(name[1]); + } + else + throw Algorithm_Not_Found(algo_spec); + + throw Invalid_Algorithm_Name(algo_spec); + } + +} --- botan/get_pbe.cpp +++ botan/get_pbe.cpp @@ -0,0 +1,70 @@ +/************************************************* +* PBE Retrieval Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Get an encrpytion PBE, set new parameters * +*************************************************/ +PBE* get_pbe(const std::string& pbe_name) + { + std::vector algo_name; + algo_name = parse_algorithm_name(pbe_name); + + if(algo_name.size() != 3) + throw Invalid_Algorithm_Name(pbe_name); + + const std::string pbe = algo_name[0]; + const std::string digest = algo_name[1]; + const std::string cipher = algo_name[2]; + + PBE* pbe_obj = 0; + + if(pbe == "PBE-PKCS5v15") + pbe_obj = new PBE_PKCS5v15(digest, cipher, ENCRYPTION); + else if(pbe == "PBE-PKCS5v20") + pbe_obj = new PBE_PKCS5v20(digest, cipher); + + if(!pbe_obj) + throw Algorithm_Not_Found(pbe_name); + + pbe_obj->new_params(); + + return pbe_obj; + } + +/************************************************* +* Get a decryption PBE, decode parameters * +*************************************************/ +PBE* get_pbe(const OID& pbe_oid, DataSource& params) + { + std::vector algo_name; + algo_name = parse_algorithm_name(OIDS::lookup(pbe_oid)); + + if(algo_name.size() < 1) + throw Invalid_Algorithm_Name(pbe_oid.as_string()); + const std::string pbe = algo_name[0]; + + if(pbe == "PBE-PKCS5v15") + { + if(algo_name.size() != 3) + throw Invalid_Algorithm_Name(pbe_oid.as_string()); + const std::string digest = algo_name[1]; + const std::string cipher = algo_name[2]; + PBE* pbe = new PBE_PKCS5v15(digest, cipher, DECRYPTION); + pbe->decode_params(params); + return pbe; + } + else if(pbe == "PBE-PKCS5v20") + return new PBE_PKCS5v20(params); + + throw Algorithm_Not_Found(pbe_oid.as_string()); + } + +} --- botan/gzip.cpp +++ botan/gzip.cpp @@ -0,0 +1,418 @@ +/************************************************* +* Gzip Compressor Source File * +* (C) 1999-2004 The Botan Project * +* * +* Based on the comp_zlib module, modified * +* by Matt Johnston. This is not a complete * +* gzip implementation (it only handles basic * +* headers). * +*************************************************/ + +/* This could be implemented a lot more cleanly if we rely on zlib >= 1.2 + * being available. the Gzip Compressor would just be a subclass of + * Zlib Compressor, with window_bits+=16 for deflateInit2(), etc */ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Allocation Information for Zlib * +*************************************************/ +class Zlib_Alloc_Info + { + public: + std::map current_allocs; + Allocator* alloc; + + Zlib_Alloc_Info() { alloc = get_allocator(); } + }; + +/************************************************* +* Allocation Function for Zlib * +*************************************************/ +void* zlib_malloc(void* info_ptr, unsigned int n, unsigned int size) + { + Zlib_Alloc_Info* info = static_cast(info_ptr); + void* ptr = info->alloc->allocate(n * size); + info->current_allocs[ptr] = n * size; + return ptr; + } + +/************************************************* +* Allocation Function for Zlib * +*************************************************/ +void zlib_free(void* info_ptr, void* ptr) + { + Zlib_Alloc_Info* info = static_cast(info_ptr); + std::map::const_iterator i = info->current_allocs.find(ptr); + if(i == info->current_allocs.end()) + throw Invalid_Argument("zlib_free: Got pointer not allocated by us"); + info->alloc->deallocate(ptr, i->second); + } +} + +/************************************************* +* Wrapper Type for Zlib z_stream * +*************************************************/ +class Zlib_Stream + { + public: + z_stream stream; + + Zlib_Stream() + { + std::memset(&stream, 0, sizeof(z_stream)); + stream.zalloc = zlib_malloc; + stream.zfree = zlib_free; + stream.opaque = new Zlib_Alloc_Info; + } + ~Zlib_Stream() + { + Zlib_Alloc_Info* info = static_cast(stream.opaque); + delete info; + std::memset(&stream, 0, sizeof(z_stream)); + } + }; + +/************************************************* +* Gzip_Compression Constructor * +*************************************************/ +Gzip_Compression::Gzip_Compression(u32bit l) : + level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE), + pipe(new Hash_Filter("CRC32")), count( 0 ) + { + zlib = 0; + } + +/************************************************* +* Start Compressing with Gzip * +*************************************************/ +void Gzip_Compression::start_msg() + { + clear(); + zlib = new Zlib_Stream; + // window_bits == -15 relies on an undocumented feature of zlib, which + // supresses the zlib header on the message. We need that since gzip doesn't + // use this header. The feature been confirmed to exist in 1.1.4, which + // everyone should be using due to security fixes. In later versions this + // feature is documented, along with the ability to do proper gzip output + // (which would be a nicer way to do things, but will have to wait until 1.2 + // becomes more widespread). + // The other settings are the defaults which deflateInit() gives + if(deflateInit2(&(zlib->stream), level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) + throw Exception("Gzip_Compression: Memory allocation error"); + put_header(); + pipe.start_msg(); + count = 0; + } + +/************************************************* +* Compress Input with Gzip * +*************************************************/ +void Gzip_Compression::write(const byte input[], u32bit length) + { + + count += length; + pipe.write(input, length); + + zlib->stream.next_in = (Bytef*)input; + zlib->stream.avail_in = length; + + while(zlib->stream.avail_in != 0) + { + zlib->stream.next_out = (Bytef*)buffer.begin(); + zlib->stream.avail_out = buffer.size(); + deflate(&(zlib->stream), Z_NO_FLUSH); + send(buffer.begin(), buffer.size() - zlib->stream.avail_out); + } + } + +/************************************************* +* Finish Compressing with Gzip * +*************************************************/ +void Gzip_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 = (Bytef*)buffer.begin(); + zlib->stream.avail_out = buffer.size(); + rc = deflate(&(zlib->stream), Z_FINISH); + send(buffer.begin(), buffer.size() - zlib->stream.avail_out); + } + + pipe.end_msg(); + put_footer(); + + clear(); + } + +/************************************************* +* Flush the Gzip Compressor * +*************************************************/ +void Gzip_Compression::flush() + { + zlib->stream.next_in = 0; + zlib->stream.avail_in = 0; + + while(true) + { + zlib->stream.next_out = (Bytef*)buffer.begin(); + zlib->stream.avail_out = buffer.size(); + deflate(&(zlib->stream), Z_FULL_FLUSH); + send(buffer.begin(), buffer.size() - zlib->stream.avail_out); + if(zlib->stream.avail_out == buffer.size()) break; + } + } + +/************************************************* +* Clean up Compression Context * +*************************************************/ +void Gzip_Compression::clear() + { + if(zlib) + { + deflateEnd(&(zlib->stream)); + delete zlib; + zlib = 0; + } + + buffer.clear(); + } + +/************************************************* +* Put a basic gzip header at the beginning * +*************************************************/ +void Gzip_Compression::put_header() + { + send(GZIP::GZIP_HEADER, sizeof(GZIP::GZIP_HEADER)); + } + +/************************************************* +* Put a gzip footer at the end * +*************************************************/ +void Gzip_Compression::put_footer() + { + + // 4 byte CRC32, and 4 byte length field + SecureVector buf(4); + SecureVector tmpbuf(4); + + pipe.read(tmpbuf.begin(), tmpbuf.size()); + + // CRC32 is the reverse order to what gzip expects. + for (int i = 0; i < 4; i++) + buf[3-i] = tmpbuf[i]; + + send(buf.begin(), buf.size()); + + // Length - LSB first + for (int i = 0; i < 4; i++) + buf[3-i] = get_byte(i, count); + + send(buf.begin(), buf.size()); + } + +/************************************************* +* Gzip_Decompression Constructor * +*************************************************/ +Gzip_Decompression::Gzip_Decompression() : buffer(DEFAULT_BUFFERSIZE), + pipe(new Hash_Filter("CRC32")), footer(0) + { + zlib = 0; + no_writes = true; + if (DEFAULT_BUFFERSIZE < sizeof(GZIP::GZIP_HEADER)) + throw Exception("DEFAULT_BUFFERSIZE is too small"); + } + +/************************************************* +* Start Decompressing with Gzip * +*************************************************/ +void Gzip_Decompression::start_msg() + { + clear(); + zlib = new Zlib_Stream; + // window_bits == -15 is raw zlib (no header) - see comment + // above for deflateInit2 + if(inflateInit2(&(zlib->stream), -15) != Z_OK) + throw Exception("Gzip_Decompression: Memory allocation error"); + pipe.start_msg(); + datacount = 0; + pos = 0; + in_footer = false; + } + +/************************************************* +* Decompress Input with Gzip * +*************************************************/ +void Gzip_Decompression::write(const byte input[], u32bit length) + { + if(length) no_writes = false; + + // If we're in the footer, take what we need, then go to the next block + if (in_footer) + { + u32bit eat_len = write_footer(input, length); + input += eat_len; + length -= eat_len; + if (length == 0) + return; + } + + // Check the gzip header + if (pos < sizeof(GZIP::GZIP_HEADER)) + { + u32bit len = std::min((u32bit)sizeof(GZIP::GZIP_HEADER)-pos, length); + u32bit cmplen = len; + // The last byte is the OS flag - we don't care about that + if (pos + len - 1 >= GZIP::HEADER_POS_OS) + cmplen--; + + if (memcmp(input, &GZIP::GZIP_HEADER[pos], cmplen) != 0) + { + throw Decoding_Error("Gzip_Decompression: Data integrity error in header"); + } + input += len; + length -= len; + pos += len; + } + + pos += length; + + zlib->stream.next_in = (Bytef*)input; + zlib->stream.avail_in = length; + + while(zlib->stream.avail_in != 0) + { + zlib->stream.next_out = (Bytef*)buffer.begin(); + 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("Gzip_Decompression: Data integrity error"); + if(rc == Z_NEED_DICT) + throw Decoding_Error("Gzip_Decompression: Need preset dictionary"); + if(rc == Z_MEM_ERROR) + throw Exception("Gzip_Decompression: Memory allocation error"); + throw Exception("Gzip_Decompression: Unknown decompress error"); + } + send(buffer.begin(), buffer.size() - zlib->stream.avail_out); + pipe.write(buffer.begin(), buffer.size() - zlib->stream.avail_out); + datacount += buffer.size() - zlib->stream.avail_out; + + // Reached the end - we now need to check the footer + if(rc == Z_STREAM_END) + { + u32bit read_from_block = length - zlib->stream.avail_in; + u32bit eat_len = write_footer((Bytef*)input + read_from_block, zlib->stream.avail_in); + read_from_block += eat_len; + input += read_from_block; + length -= read_from_block; + zlib->stream.next_in = (Bytef*)input; + zlib->stream.avail_in = length; + } + } + } + +/************************************************* +* Store the footer bytes * +*************************************************/ +u32bit Gzip_Decompression::write_footer(const byte input[], u32bit length) + { + if (footer.size() >= GZIP::FOOTER_LENGTH) + throw Decoding_Error("Gzip_Decompression: Data integrity error in footer"); + + u32bit eat_len = std::min(GZIP::FOOTER_LENGTH-footer.size(), length); + footer.append(input, eat_len); + + if (footer.size() == GZIP::FOOTER_LENGTH) + { + check_footer(); + start_msg(); + } + + return eat_len; + } + +/************************************************* +* Check the gzip footer * +*************************************************/ +void Gzip_Decompression::check_footer() + { + if(no_writes) return; + + if (footer.size() != GZIP::FOOTER_LENGTH) + throw Exception("Gzip_Decompression: Error finalizing decompression"); + + pipe.end_msg(); + + // 4 byte CRC32, and 4 byte length field + SecureVector buf(4); + SecureVector tmpbuf(4); + pipe.read(tmpbuf.begin(), tmpbuf.size()); + + // CRC32 is the reverse order to what gzip expects. + for (int i = 0; i < 4; i++) + buf[3-i] = tmpbuf[i]; + + tmpbuf.set(footer.begin(), 4); + if (buf != tmpbuf) + throw Exception("Gzip_Decompression: Data integrity error - CRC32 error"); + + // Check the length matches - it is encoded LSB-first + for (int i = 0; i < 4; i++) + { + if (footer.begin()[GZIP::FOOTER_LENGTH-1-i] != get_byte(i, datacount)) + throw Exception("Gzip_Decompression: Data integrity error - incorrect length"); + } + + } + +/************************************************* +* Finish Decompressing with Gzip * +*************************************************/ +void Gzip_Decompression::end_msg() + { + + // All messages should end with a footer, and when a footer is successfully + // read, start_msg() will be called. + if(no_writes) return; + + throw Exception("Gzip_Decompression: didn't find footer"); + + } + +/************************************************* +* Clean up Decompression Context * +*************************************************/ +void Gzip_Decompression::clear() + { + no_writes = true; + + if(zlib) + { + inflateEnd(&(zlib->stream)); + delete zlib; + zlib = 0; + } + + buffer.clear(); + footer.clear(); + pos = 0; + datacount = 0; + } + +} --- botan/gzip.h +++ botan/gzip.h @@ -0,0 +1,85 @@ +/************************************************* +* Gzip Compressor Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_EXT_GZIP_H__ +#define BOTAN_EXT_GZIP_H__ + +#include +#include + +namespace Botan { + +namespace GZIP { + + /* A basic header - we only need to set the IDs and compression method */ + const byte GZIP_HEADER[] = { + 0x1f, 0x8b, /* Magic ID bytes */ + 0x08, /* Compression method of 'deflate' */ + 0x00, /* Flags all empty */ + 0x00, 0x00, 0x00, 0x00, /* MTIME */ + 0x00, /* Extra flags */ + 0xff, /* Operating system (unknown) */ + }; + + const unsigned int HEADER_POS_OS = 9; + + const unsigned int FOOTER_LENGTH = 8; + +} + +/************************************************* +* Gzip Compression Filter * +*************************************************/ +class Gzip_Compression : public Filter + { + public: + void write(const byte input[], u32bit length); + void start_msg(); + void end_msg(); + + void flush(); + + Gzip_Compression(u32bit = 6); + ~Gzip_Compression() { clear(); } + private: + void clear(); + void put_header(); + void put_footer(); + const u32bit level; + SecureVector buffer; + class Zlib_Stream* zlib; + Pipe pipe; /* A pipe for the crc32 processing */ + u32bit count; + }; + +/************************************************* +* Gzip Decompression Filter * +*************************************************/ +class Gzip_Decompression : public Filter + { + public: + void write(const byte input[], u32bit length); + void start_msg(); + void end_msg(); + + Gzip_Decompression(); + ~Gzip_Decompression() { clear(); } + private: + u32bit write_footer(const byte input[], u32bit length); + void check_footer(); + void clear(); + SecureVector buffer; + class Zlib_Stream* zlib; + bool no_writes; + u32bit pos; /* Current position in the message */ + Pipe pipe; /* A pipe for the crc32 processing */ + u32bit datacount; /* Amount of uncompressed output */ + SecureVector footer; + bool in_footer; + }; + +} + +#endif --- botan/hash_id.cpp +++ botan/hash_id.cpp @@ -0,0 +1,97 @@ +/************************************************* +* Hash Function Identification Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace PKCS_IDS { + +const byte MD2_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 }; + +const byte MD5_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + +const byte RIPEMD_128_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x02, 0x05, 0x00, 0x04, 0x14 }; + +const byte RIPEMD_160_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x01, 0x05, 0x00, 0x04, 0x14 }; + +const byte SHA_160_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, +0x1A, 0x05, 0x00, 0x04, 0x14 }; + +const byte SHA_256_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; + +const byte SHA_384_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; + +const byte SHA_512_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; + +const byte TIGER_ID[] = { +0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, +0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 }; + +} + +/************************************************* +* Return the HashID, as specified by PKCS * +*************************************************/ +MemoryVector pkcs_hash_id(const std::string& name_or_alias) + { + const std::string name = deref_alias(name_or_alias); + + MemoryVector out; + if(name == "MD2") + out.set(PKCS_IDS::MD2_ID, sizeof(PKCS_IDS::MD2_ID)); + else if(name == "MD5") + out.set(PKCS_IDS::MD5_ID, sizeof(PKCS_IDS::MD5_ID)); + else if(name == "RIPEMD-128") + out.set(PKCS_IDS::RIPEMD_128_ID, sizeof(PKCS_IDS::RIPEMD_128_ID)); + else if(name == "RIPEMD-160") + out.set(PKCS_IDS::RIPEMD_160_ID, sizeof(PKCS_IDS::RIPEMD_160_ID)); + else if(name == "SHA-160") + out.set(PKCS_IDS::SHA_160_ID, sizeof(PKCS_IDS::SHA_160_ID)); + else if(name == "SHA-256") + out.set(PKCS_IDS::SHA_256_ID, sizeof(PKCS_IDS::SHA_256_ID)); + else if(name == "SHA-384") + out.set(PKCS_IDS::SHA_384_ID, sizeof(PKCS_IDS::SHA_384_ID)); + else if(name == "SHA-512") + out.set(PKCS_IDS::SHA_512_ID, sizeof(PKCS_IDS::SHA_512_ID)); + else if(name == "Tiger(24,3)") + out.set(PKCS_IDS::TIGER_ID, sizeof(PKCS_IDS::TIGER_ID)); + return out; + } + +/************************************************* +* Return the HashID, as specified by IEEE 1363 * +*************************************************/ +byte ieee1363_hash_id(const std::string& name_or_alias) + { + const std::string name = deref_alias(name_or_alias); + + if(name == "RIPEMD-160") return 0x31; + if(name == "RIPEMD-128") return 0x32; + if(name == "SHA-160") return 0x33; + if(name == "SHA-256") return 0x34; + if(name == "SHA-512") return 0x35; + if(name == "SHA-384") return 0x36; + if(name == "Whirlpool") return 0x37; + return 0; + } + +} --- botan/hex.cpp +++ botan/hex.cpp @@ -0,0 +1,180 @@ +/************************************************* +* Hex Encoder/Decoder Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Hex_Encoder Constructor * +*************************************************/ +Hex_Encoder::Hex_Encoder(bool breaks, u32bit length, Case c) : + casing(c), line_length(breaks ? length : 0) + { + in.create(64); + out.create(2*in.size()); + counter = position = 0; + } + +/************************************************* +* Hex_Encoder Constructor * +*************************************************/ +Hex_Encoder::Hex_Encoder(Case c) : casing(c), line_length(0) + { + in.create(64); + out.create(2*in.size()); + counter = position = 0; + } + +/************************************************* +* Hex Encoding Operation * +*************************************************/ +void Hex_Encoder::encode(byte in, byte out[2], Hex_Encoder::Case casing) + { + const byte* BIN_TO_HEX = ((casing == Uppercase) ? BIN_TO_HEX_UPPER : + BIN_TO_HEX_LOWER); + + out[0] = BIN_TO_HEX[((in >> 4) & 0x0F)]; + out[1] = BIN_TO_HEX[((in ) & 0x0F)]; + } + +/************************************************* +* Encode and send a block * +*************************************************/ +void Hex_Encoder::encode_and_send(const byte block[], u32bit length) + { + for(u32bit j = 0; j != length; j++) + encode(block[j], out + 2*j, casing); + + if(line_length == 0) + send(out, 2*length); + else + { + u32bit remaining = 2*length, offset = 0; + while(remaining) + { + u32bit 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[], u32bit length) + { + in.copy(position, input, length); + if(position + length >= in.size()) + { + encode_and_send(in, 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(); + } + in.copy(input, length); + position = 0; + } + position += length; + } + +/************************************************* +* Flush buffers * +*************************************************/ +void Hex_Encoder::end_msg() + { + encode_and_send(in, position); + if(counter && line_length) + send('\n'); + counter = position = 0; + } + +/************************************************* +* Hex_Decoder Constructor * +*************************************************/ +Hex_Decoder::Hex_Decoder(Decoder_Checking c) : checking(c) + { + in.create(64); + out.create(in.size() / 2); + position = 0; + } + +/************************************************* +* Check if a character is a valid hex char * +*************************************************/ +bool Hex_Decoder::is_valid(byte in) + { + return (HEX_TO_BIN[in] != 0x80); + } + +/************************************************* +* Handle processing an invalid character * +*************************************************/ +void Hex_Decoder::handle_bad_char(byte c) + { + if(checking == NONE) return; + if((checking == IGNORE_WS) && is_space(c)) return; + throw Decoding_Error("Hex_Decoder: Invalid hex character: " + c); + } + +/************************************************* +* Hex Decoding Operation * +*************************************************/ +byte Hex_Decoder::decode(const byte hex[2]) + { + return (byte)((HEX_TO_BIN[hex[0]] << 4) | HEX_TO_BIN[hex[1]]); + } + +/************************************************* +* Decode and send a block * +*************************************************/ +void Hex_Decoder::decode_and_send(const byte block[], u32bit length) + { + for(u32bit j = 0; j != length / 2; j++) + out[j] = decode(block + 2*j); + send(out, length / 2); + } + +/************************************************* +* Convert some data from hex format * +*************************************************/ +void Hex_Decoder::write(const byte input[], u32bit length) + { + for(u32bit j = 0; j != length; j++) + { + if(is_valid(input[j])) + in[position++] = input[j]; + else + handle_bad_char(input[j]); + if(position == in.size()) + { + decode_and_send(in, in.size()); + position = 0; + } + } + } + +/************************************************* +* Flush buffers * +*************************************************/ +void Hex_Decoder::end_msg() + { + decode_and_send(in, position); + position = 0; + } + +} --- botan/hex.h +++ botan/hex.h @@ -0,0 +1,63 @@ +/************************************************* +* Hex Encoder/Decoder Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_HEX_H__ +#define BOTAN_HEX_H__ + +#include + +namespace Botan { + +/************************************************* +* Hex Encoder * +*************************************************/ +class Hex_Encoder : public Filter + { + public: + enum Case { Uppercase, Lowercase }; + static void encode(byte, byte[2], Case = Uppercase); + + void write(const byte[], u32bit); + void end_msg(); + + Hex_Encoder(Case); + Hex_Encoder(bool = false, u32bit = 72, Case = Uppercase); + private: + void encode_and_send(const byte[], u32bit); + static const byte BIN_TO_HEX_UPPER[16]; + static const byte BIN_TO_HEX_LOWER[16]; + + const Case casing; + const u32bit line_length; + SecureVector in, out; + u32bit position, counter; + }; + +/************************************************* +* Hex Decoder * +*************************************************/ +class Hex_Decoder : public Filter + { + public: + static byte decode(const byte[2]); + static bool is_valid(byte); + + void write(const byte[], u32bit); + void end_msg(); + + Hex_Decoder(Decoder_Checking = NONE); + private: + void decode_and_send(const byte[], u32bit); + void handle_bad_char(byte); + static const byte HEX_TO_BIN[256]; + + const Decoder_Checking checking; + SecureVector in, out; + u32bit position; + }; + +} + +#endif --- botan/hmac.cpp +++ botan/hmac.cpp @@ -0,0 +1,88 @@ +/************************************************* +* HMAC Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Update a HMAC Calculation * +*************************************************/ +void HMAC::add_data(const byte input[], u32bit 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(const byte key[], u32bit length) + { + hash->clear(); + std::fill(i_key.begin(), i_key.end(), 0x36); + std::fill(o_key.begin(), o_key.end(), 0x5C); + + SecureVector hmac_key(key, length); + if(hmac_key.size() > hash->HASH_BLOCK_SIZE) + hmac_key = hash->process(hmac_key); + + xor_buf(i_key, hmac_key, hmac_key.size()); + xor_buf(o_key, hmac_key, hmac_key.size()); + hash->update(i_key); + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void HMAC::clear() throw() + { + hash->clear(); + i_key.clear(); + o_key.clear(); + } + +/************************************************* +* 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->name()); + } + +/************************************************* +* HMAC Constructor * +*************************************************/ +HMAC::HMAC(const std::string& hash_name) : + MessageAuthenticationCode(output_length_of(hash_name), 1, 64), + hash(get_hash(hash_name)) + { + if(hash->HASH_BLOCK_SIZE == 0) + throw Invalid_Argument("HMAC cannot be used with " + hash->name()); + i_key.create(hash->HASH_BLOCK_SIZE); + o_key.create(hash->HASH_BLOCK_SIZE); + } + +} --- botan/hmac.h +++ botan/hmac.h @@ -0,0 +1,34 @@ +/************************************************* +* HMAC Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_HMAC_H__ +#define BOTAN_HMAC_H__ + +#include + +namespace Botan { + +/************************************************* +* HMAC * +*************************************************/ +class HMAC : public MessageAuthenticationCode + { + public: + void clear() throw(); + std::string name() const; + MessageAuthenticationCode* clone() const; + HMAC(const std::string&); + ~HMAC() { delete hash; } + private: + void add_data(const byte[], u32bit); + void final_result(byte[]); + void key(const byte[], u32bit); + HashFunction* hash; + SecureVector i_key, o_key; + }; + +} + +#endif --- botan/if_algo.cpp +++ botan/if_algo.cpp @@ -0,0 +1,155 @@ +/************************************************* +* IF Scheme Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Return the X.509 public key encoding * +*************************************************/ +MemoryVector IF_Scheme_PublicKey::DER_encode_pub() const + { + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, n); + DER::encode(encoder, e); + encoder.end_sequence(); + return encoder.get_contents(); + } + +/************************************************* +* Return the X.509 parameters encoding * +*************************************************/ +MemoryVector IF_Scheme_PublicKey::DER_encode_params() const + { + DER_Encoder encoder; + DER::encode_null(encoder); + return encoder.get_contents(); + } + +/************************************************* +* Decode X.509 public key encoding * +*************************************************/ +void IF_Scheme_PublicKey::BER_decode_pub(DataSource& source) + { + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, n); + BER::decode(sequence, e); + sequence.verify_end(); + + X509_load_hook(); + } + +/************************************************* +* Decode X.509 algorithm parameters * +*************************************************/ +void IF_Scheme_PublicKey::BER_decode_params(DataSource& source) + { + byte dummy = 0; + while(!source.end_of_data()) + source.read_byte(dummy); + } + +/************************************************* +* Return the PKCS #1 private key encoding * +*************************************************/ +SecureVector IF_Scheme_PrivateKey::DER_encode_priv() const + { + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 0); + DER::encode(encoder, n); + DER::encode(encoder, e); + DER::encode(encoder, d); + DER::encode(encoder, p); + DER::encode(encoder, q); + DER::encode(encoder, d1); + DER::encode(encoder, d2); + DER::encode(encoder, c); + encoder.end_sequence(); + return encoder.get_contents(); + } + +/************************************************* +* Decode a PKCS #1 private key encoding * +*************************************************/ +void IF_Scheme_PrivateKey::BER_decode_priv(DataSource& source) + { + u32bit version; + + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, version); + if(version != 0) + throw Decoding_Error(algo_name() + ": Unknown PKCS #1 key version"); + BER::decode(sequence, n); + BER::decode(sequence, e); + BER::decode(sequence, d); + BER::decode(sequence, p); + BER::decode(sequence, q); + BER::decode(sequence, d1); + BER::decode(sequence, d2); + BER::decode(sequence, c); + sequence.verify_end(); + + PKCS8_load_hook(); + check_loaded_private(); + } + +/************************************************* +* Algorithm Specific X.509 Initialization Code * +*************************************************/ +void IF_Scheme_PublicKey::X509_load_hook() + { + core = IF_Core(e, n); + check_loaded_public(); + } + +/************************************************* +* Algorithm Specific PKCS #8 Initialization Code * +*************************************************/ +void IF_Scheme_PrivateKey::PKCS8_load_hook() + { + if(n == 0) n = p * q; + if(d1 == 0) d1 = d % (p - 1); + if(d2 == 0) d2 = d % (q - 1); + if(c == 0) c = inverse_mod(q, p); + + core = IF_Core(e, n, d, p, q, d1, d2, c); + } + +/************************************************* +* Check IF Scheme Public Parameters * +*************************************************/ +bool IF_Scheme_PublicKey::check_key(bool) const + { + if(n < 35 || n.is_even() || e < 2) + return false; + return true; + } + +/************************************************* +* Check IF Scheme Private Parameters * +*************************************************/ +bool IF_Scheme_PrivateKey::check_key(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) || !check_prime(q)) + return false; + return true; + } + +} --- botan/if_algo.h +++ botan/if_algo.h @@ -0,0 +1,64 @@ +/************************************************* +* IF Scheme Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_IF_ALGO_H__ +#define BOTAN_IF_ALGO_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* IF Public Key * +*************************************************/ +class IF_Scheme_PublicKey : public virtual X509_PublicKey + { + public: + bool check_key(bool) const; + + const BigInt& get_n() const { return n; } + const BigInt& get_e() const { return e; } + + u32bit max_input_bits() const { return (n.bits() - 1); } + + virtual ~IF_Scheme_PublicKey() {} + protected: + virtual void X509_load_hook(); + BigInt n, e; + IF_Core core; + private: + MemoryVector DER_encode_pub() const; + MemoryVector DER_encode_params() const; + void BER_decode_params(DataSource&); + void BER_decode_pub(DataSource&); + }; + +/************************************************* +* IF Private Key * +*************************************************/ +class IF_Scheme_PrivateKey : public virtual IF_Scheme_PublicKey, + public virtual PKCS8_PrivateKey + { + public: + bool check_key(bool) const; + + const BigInt& get_p() const { return p; } + const BigInt& get_q() const { return q; } + const BigInt& get_d() const { return d; } + + virtual ~IF_Scheme_PrivateKey() {} + protected: + virtual void PKCS8_load_hook(); + BigInt d, p, q, d1, d2, c; + private: + SecureVector DER_encode_priv() const; + void BER_decode_priv(DataSource&); + }; + +} + +#endif --- botan/inifile.cpp +++ botan/inifile.cpp @@ -0,0 +1,139 @@ +/************************************************* +* Configuration Reader Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Strip comments and whitespace from line * +*************************************************/ +std::string strip_whitespace(const std::string& line) + { + bool is_escaped = false, in_quote = false, in_string = false; + std::string new_line; + + for(std::string::const_iterator j = line.begin(); j != line.end(); j++) + { + const char c = *j; + + if(c == '"' && !is_escaped && !in_string) + { in_quote = !in_quote; continue; } + if(c == '\'' && !is_escaped && !in_quote) + { in_string = !in_string; continue; } + if(c == '#' && !is_escaped && !in_quote && !in_string) + return new_line; + if(c == '\\' && !is_escaped) { is_escaped = true; continue; } + + if(is_space(c) && !in_quote && !in_string && !is_escaped) + continue; + + new_line += c; + is_escaped = false; + } + + return new_line; + } + +/************************************************* +* Do variable interpolation * +*************************************************/ +std::string interpolate(const std::string& value, + const std::map& variables) + { + std::string variable, suffix; + + if(value.find('.') == std::string::npos) + variable = value; + else + { + variable = value.substr(0, value.find('.')); + suffix = value.substr(value.find('.'), std::string::npos); + } + + if(variables.find(variable) != variables.end()) + { + const std::string result = variables.find(variable)->second; + if(variable == result) + return value; + return interpolate(result, variables) + suffix; + } + return value; + } + +} + +namespace Config { + +/************************************************* +* Load a configuration file * +*************************************************/ +void load(const std::string& fsname) + { + std::ifstream config(fsname.c_str()); + + if(!config) + throw Config_Error("Could not open config file " + fsname); + + u32bit line_no = 0; + std::string line, section; + std::map variables; + + while(std::getline(config, line)) + { + line_no++; + + line = strip_whitespace(line); + + if(line == "") + continue; + + if(line[0] == '[' && line[line.size()-1] == ']') + { + section = line.substr(1, line.size() - 2); + if(section == "") + throw Config_Error("Empty section name", line_no); + continue; + } + + if(section == "") + throw Config_Error("Section must be set before assignment", line_no); + + std::vector name_and_value; + try { + name_and_value = split_on(line, '='); + } + catch(Format_Error) + { + throw Config_Error("Bad assignment: " + line, line_no); + } + + if(name_and_value.size() != 2) + throw Config_Error("Bad line: " + line, line_no); + const std::string name = name_and_value[0]; + const std::string value = interpolate(name_and_value[1], variables); + + if(variables.find(name) == variables.end()) + variables[name] = value; + + if(section == "oids") + OIDS::add_oid(OID(value), name); + else if(section == "aliases") + add_alias(name, value); + else + set(section + '/' + name, value); + } + } + +} + +} --- botan/init.cpp +++ botan/init.cpp @@ -0,0 +1,309 @@ +/************************************************* +* Initialization Function Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_EXT_MUTEX_PTHREAD) + #include +#elif defined(BOTAN_EXT_MUTEX_WIN32) + #include +#elif defined(BOTAN_EXT_MUTEX_QT) + #include +#endif + +#if defined(BOTAN_EXT_ALLOC_MMAP) + #include +#endif + +#if defined(BOTAN_EXT_TIMER_HARDWARE) + #include +#elif defined(BOTAN_EXT_TIMER_POSIX) + #include +#elif defined(BOTAN_EXT_TIMER_UNIX) + #include +#elif defined(BOTAN_EXT_TIMER_WIN32) + #include +#endif + +#if defined(BOTAN_EXT_ENGINE_AEP) + #include +#endif + +#if defined(BOTAN_EXT_ENGINE_GNU_MP) + #include +#endif + +#if defined(BOTAN_EXT_ENGINE_OPENSSL) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_AEP) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_EGD) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) + #include +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_FTW) + #include +#endif + +namespace Botan { + +/************************************************* +* Library Initialization * +*************************************************/ +LibraryInitializer::LibraryInitializer(const std::string& arg_string) + { + Init::initialize(arg_string); + } + +/************************************************* +* Library Shutdown * +*************************************************/ +LibraryInitializer::~LibraryInitializer() + { + Init::deinitialize(); + } + +namespace Init { + +namespace { + +/************************************************* +* Register a mutex type, if possible * +*************************************************/ +void set_mutex() + { +#if defined(BOTAN_EXT_MUTEX_PTHREAD) + set_mutex_type(new Pthread_Mutex); +#elif defined(BOTAN_EXT_MUTEX_WIN32) + set_mutex_type(new Win32_Mutex); +#elif defined(BOTAN_EXT_MUTEX_QT) + set_mutex_type(new Qt_Mutex); +#else + throw Exception("LibraryInitializer: thread safety impossible"); +#endif + } + +/************************************************* +* Register a high resolution timer, if possible * +*************************************************/ +void set_timer() + { +#if defined(BOTAN_EXT_TIMER_HARDWARE) + set_timer_type(new Hardware_Timer); +#elif defined(BOTAN_EXT_TIMER_POSIX) + set_timer_type(new POSIX_Timer); +#elif defined(BOTAN_EXT_TIMER_UNIX) + set_timer_type(new Unix_Timer); +#elif defined(BOTAN_EXT_TIMER_WIN32) + set_timer_type(new Win32_Timer); +#endif + } + +/************************************************* +* Register any usable entropy sources * +*************************************************/ +void add_entropy_sources() + { + Global_RNG::add_es(new File_EntropySource); + +#if defined(BOTAN_EXT_ENTROPY_SRC_AEP) + Global_RNG::add_es(new AEP_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_EGD) + Global_RNG::add_es(new EGD_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) + Global_RNG::add_es(new Win32_CAPI_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) + Global_RNG::add_es(new Win32_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) + Global_RNG::add_es(new Unix_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) + Global_RNG::add_es(new BeOS_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_FTW) + Global_RNG::add_es(new FTW_EntropySource); +#endif + } + +/************************************************* +* Register a more secure allocator, if possible * +*************************************************/ +void set_safe_allocator() + { +#if defined(BOTAN_EXT_ALLOC_MMAP) + add_allocator_type("mmap", new MemoryMapping_Allocator); + set_default_allocator("mmap"); +#endif + } + +/************************************************* +* Register any usable engines * +*************************************************/ +void set_engines() + { +#if defined(BOTAN_EXT_ENGINE_AEP) + Botan::Engine_Core::add_engine(new Botan::AEP_Engine); +#endif + +#if defined(BOTAN_EXT_ENGINE_GNU_MP) + Botan::Engine_Core::add_engine(new Botan::GMP_Engine); +#endif + +#if defined(BOTAN_EXT_ENGINE_OPENSSL) + Botan::Engine_Core::add_engine(new Botan::OpenSSL_Engine); +#endif + } + +/************************************************* +* Parse the options string * +*************************************************/ +std::map parse_args(const std::string& arg_string) + { + std::map arg_map; + std::vector args = split_on(arg_string, ' '); + for(u32bit j = 0; j != args.size(); j++) + { + if(args[j].find('=') == std::string::npos) + arg_map[args[j]] = ""; + else + { + std::vector name_and_value = split_on(args[j], '='); + arg_map[name_and_value[0]] = name_and_value[1]; + } + } + + return arg_map; + } + +/************************************************* +* Check if an option is set in the argument * +*************************************************/ +bool arg_set(const std::map& args, + const std::string& option) + { + return (args.find(option) != args.end()); + } + +} + +/************************************************* +* Library Initialization * +*************************************************/ +void initialize(const std::string& arg_string) + { + std::map args = parse_args(arg_string); + + if(arg_set(args, "thread_safe")) + set_mutex(); + + set_default_options(); + startup_memory_subsystem(); + + init_lookup_tables(); + + if(arg_set(args, "secure_memory")) + set_safe_allocator(); + set_timer(); + + if(!arg_set(args, "no_aliases")) add_default_aliases(); + if(!arg_set(args, "no_oids")) add_default_oids(); + if(arg_set(args, "config") && args["config"] != "") + Config::load(args["config"]); + + startup_engines(); + if(arg_set(args, "use_engines")) + set_engines(); + init_rng_subsystem(); + + if(arg_set(args, "fips140")) + set_global_rngs(new FIPS_186_RNG, new FIPS_186_RNG); + else + set_global_rngs(new Randpool, new ANSI_X917_RNG); + + add_entropy_sources(); + + if(!FIPS140::passes_self_tests()) + { + deinitialize(); + throw Self_Test_Failure("FIPS-140 startup tests"); + } + + const u32bit min_entropy = Config::get_u32bit("rng/min_entropy"); + + if(min_entropy != 0 && !arg_set(args, "no_rng_seed")) + { + u32bit total_bits = 0; + for(u32bit j = 0; j != 4; j++) + { + total_bits += Global_RNG::seed(true, min_entropy - total_bits); + if(total_bits >= min_entropy) + break; + } + + if(total_bits < min_entropy) + throw PRNG_Unseeded("Unable to collect sufficient entropy"); + } + } + +/************************************************* +* Library Shutdown * +*************************************************/ +void deinitialize() + { + shutdown_engines(); + shutdown_rng_subsystem(); + set_global_rngs(0, 0); + destroy_lookup_tables(); + destroy_dl_groups(); + set_timer_type(0); + set_mutex_type(0); + shutdown_memory_subsystem(); + } + +} + +} --- botan/init.h +++ botan/init.h @@ -0,0 +1,52 @@ +/************************************************* +* Library Initialization Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_INIT_H__ +#define BOTAN_INIT_H__ + +#include +#include +#include +#include + +namespace Botan { + +namespace Init { + +/************************************************* +* Main Library Initialization/Shutdown Functions * +*************************************************/ +void initialize(const std::string& = ""); +void deinitialize(); + +/************************************************* +* Internal Initialization/Shutdown Functions * +*************************************************/ +void set_mutex_type(Mutex*); +void set_timer_type(Timer*); + +void startup_memory_subsystem(); +void shutdown_memory_subsystem(); +void startup_engines(); +void shutdown_engines(); + +void set_default_options(); +void destroy_dl_groups(); + +} + +/************************************************* +* Library Initialization/Shutdown Object * +*************************************************/ +class LibraryInitializer + { + public: + LibraryInitializer(const std::string& = ""); + ~LibraryInitializer(); + }; + +} + +#endif --- botan/kdf.cpp +++ botan/kdf.cpp @@ -0,0 +1,73 @@ +/************************************************* +* KDF1/KDF2 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* KDF1 Key Derivation Mechanism * +*************************************************/ +SecureVector KDF1::derive(u32bit, + const byte secret[], u32bit secret_len, + const byte P[], u32bit P_len) const + { + std::auto_ptr hash(get_hash(hash_name)); + + hash->update(secret, secret_len); + hash->update(P, P_len); + return hash->final(); + } + +/************************************************* +* KDF1 Constructor * +*************************************************/ +KDF1::KDF1(const std::string& h_name) : hash_name(h_name) + { + if(!have_hash(hash_name)) + throw Algorithm_Not_Found(hash_name); + } + +/************************************************* +* KDF2 Key Derivation Mechanism * +*************************************************/ +SecureVector KDF2::derive(u32bit out_len, + const byte secret[], u32bit secret_len, + const byte P[], u32bit P_len) const + { + SecureVector output; + u32bit counter = 1; + + std::auto_ptr hash(get_hash(hash_name)); + while(out_len) + { + hash->update(secret, secret_len); + for(u32bit j = 0; j != 4; j++) + hash->update(get_byte(j, counter)); + hash->update(P, P_len); + SecureVector hash_result = hash->final(); + + u32bit added = std::min(hash_result.size(), out_len); + output.append(hash_result, added); + out_len -= added; + + counter++; + } + + return output; + } + +/************************************************* +* KDF2 Constructor * +*************************************************/ +KDF2::KDF2(const std::string& h_name) : hash_name(h_name) + { + if(!have_hash(hash_name)) + throw Algorithm_Not_Found(hash_name); + } + +} --- botan/kdf.h +++ botan/kdf.h @@ -0,0 +1,80 @@ +/************************************************* +* KDF Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_KDF_H__ +#define BOTAN_KDF_H__ + +#include + +namespace Botan { + +/************************************************* +* KDF1 * +*************************************************/ +class KDF1 : public KDF + { + public: + KDF1(const std::string&); + private: + SecureVector derive(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + + const std::string hash_name; + }; + +/************************************************* +* KDF2 * +*************************************************/ +class KDF2 : public KDF + { + public: + + KDF2(const std::string&); + private: + SecureVector derive(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + const std::string hash_name; + }; + +/************************************************* +* SSL3 PRF * +*************************************************/ +class SSL3_PRF : public KDF + { + private: + SecureVector derive(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + }; + +/************************************************* +* TLS PRF * +*************************************************/ +class TLS_PRF : public KDF + { + private: + SecureVector derive(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + SecureVector P_hash(const std::string&, u32bit, + const byte[], u32bit, + const byte[], u32bit) const; + }; + +/************************************************* +* X9.42 PRF * +*************************************************/ +class X942_PRF : public KDF + { + public: + X942_PRF(const std::string&); + private: + SecureVector derive(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + + std::string key_wrap_oid; + }; + +} + +#endif --- botan/keypair.cpp +++ botan/keypair.cpp @@ -0,0 +1,58 @@ +/************************************************* +* Keypair Checks Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace KeyPair { + +/************************************************* +* Check an encryption key pair for consistency * +*************************************************/ +void check_key(PK_Encryptor* encryptor, PK_Decryptor* decryptor) + { + std::auto_ptr enc(encryptor); + std::auto_ptr dec(decryptor); + + SecureVector message(enc->maximum_input_size() - 1); + Global_RNG::randomize(message, message.size(), Nonce); + + SecureVector ciphertext = enc->encrypt(message); + if(ciphertext == message) + throw Self_Test_Failure("Encryption key pair consistency failure"); + + SecureVector message2 = dec->decrypt(ciphertext); + if(message != message2) + throw Self_Test_Failure("Encryption key pair consistency failure"); + } + +/************************************************* +* Check a signature key pair for consistency * +*************************************************/ +void check_key(PK_Signer* signer, PK_Verifier* verifier) + { + std::auto_ptr sig(signer); + std::auto_ptr ver(verifier); + + SecureVector message(16); + Global_RNG::randomize(message, message.size(), Nonce); + + SecureVector signature = sig->sign_message(message); + + if(!ver->verify_message(message, signature)) + throw Self_Test_Failure("Signature key pair consistency failure"); + + message[0]++; + if(ver->verify_message(message, signature)) + throw Self_Test_Failure("Signature key pair consistency failure"); + } + +} + +} --- botan/keypair.h +++ botan/keypair.h @@ -0,0 +1,25 @@ +/************************************************* +* Keypair Checks Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_KEYPAIR_H__ +#define BOTAN_KEYPAIR_H__ + +#include + +namespace Botan { + +namespace KeyPair { + +/************************************************* +* Check key pair consistency * +*************************************************/ +void check_key(PK_Encryptor*, PK_Decryptor*); +void check_key(PK_Signer*, PK_Verifier*); + +} + +} + +#endif --- botan/license.txt +++ botan/license.txt @@ -0,0 +1,23 @@ +Copyright (C) 1999-2004 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions, and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + +IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --- botan/look_add.h +++ botan/look_add.h @@ -0,0 +1,40 @@ +/************************************************* +* Lookup Table Management Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_LOOKUP_MANGEMENT_H__ +#define BOTAN_LOOKUP_MANGEMENT_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Add an algorithm to the lookup table * +*************************************************/ +void add_algorithm(BlockCipher*); +void add_algorithm(StreamCipher*); +void add_algorithm(HashFunction*); +void add_algorithm(MessageAuthenticationCode*); +void add_algorithm(S2K*); +void add_algorithm(BlockCipherModePaddingMethod*); + +/************************************************* +* Add an alias for an algorithm * +*************************************************/ +void add_alias(const std::string&, const std::string&); + +/************************************************* +* Lookup table startup/shutdown * +*************************************************/ +void init_lookup_tables(); +void destroy_lookup_tables(); +void add_default_oids(); +void add_default_aliases(); + +} + +#endif --- botan/look_pk.cpp +++ botan/look_pk.cpp @@ -0,0 +1,74 @@ +/************************************************* +* PK Algorithm Lookup Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Get a PK_Encryptor object * +*************************************************/ +PK_Encryptor* get_pk_encryptor(const PK_Encrypting_Key& key, + const std::string& eme) + { + return new PK_Encryptor_MR_with_EME(key, eme); + } + +/************************************************* +* Get a PK_Decryptor object * +*************************************************/ +PK_Decryptor* get_pk_decryptor(const PK_Decrypting_Key& key, + const std::string& eme) + { + return new PK_Decryptor_MR_with_EME(key, eme); + } + +/************************************************* +* Get a PK_Signer object * +*************************************************/ +PK_Signer* get_pk_signer(const PK_Signing_Key& key, + const std::string& encoding, + Signature_Format sig_format) + { + PK_Signer* signer = new PK_Signer(key, encoding); + signer->set_output_format(sig_format); + return signer; + } + +/************************************************* +* Get a PK_Verifier object * +*************************************************/ +PK_Verifier* get_pk_verifier(const PK_Verifying_with_MR_Key& key, + const std::string& encoding, + Signature_Format sig_format) + { + PK_Verifier* verifier = new PK_Verifier_with_MR(key, encoding); + verifier->set_input_format(sig_format); + return verifier; + } + +/************************************************* +* Get a PK_Verifier object * +*************************************************/ +PK_Verifier* get_pk_verifier(const PK_Verifying_wo_MR_Key& key, + const std::string& encoding, + Signature_Format sig_format) + { + PK_Verifier* verifier = new PK_Verifier_wo_MR(key, encoding); + verifier->set_input_format(sig_format); + return verifier; + } + +/************************************************* +* Get a PK_Key_Agreement object * +*************************************************/ +PK_Key_Agreement* get_pk_kas(const PK_Key_Agreement_Key& key, + const std::string& kdf) + { + return new PK_Key_Agreement(key, kdf); + } + +} --- botan/look_pk.h +++ botan/look_pk.h @@ -0,0 +1,33 @@ +/************************************************* +* PK Algorithm Lookup Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PK_LOOKUP_H__ +#define BOTAN_PK_LOOKUP_H__ + +#include + +namespace Botan { + +/************************************************* +* Get an PK algorithm object * +*************************************************/ +PK_Encryptor* get_pk_encryptor(const PK_Encrypting_Key&, const std::string&); +PK_Decryptor* get_pk_decryptor(const PK_Decrypting_Key&, const std::string&); + +PK_Signer* get_pk_signer(const PK_Signing_Key&, const std::string&, + Signature_Format = IEEE_1363); + +PK_Verifier* get_pk_verifier(const PK_Verifying_with_MR_Key&, + const std::string&, + Signature_Format = IEEE_1363); +PK_Verifier* get_pk_verifier(const PK_Verifying_wo_MR_Key&, + const std::string&, + Signature_Format = IEEE_1363); + +PK_Key_Agreement* get_pk_kas(const PK_Key_Agreement_Key&, const std::string&); + +} + +#endif --- botan/lookup.cpp +++ botan/lookup.cpp @@ -0,0 +1,171 @@ +/************************************************* +* Algorithm Lookup Table Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Name to algorithm mapping tables * +*************************************************/ +std::map s2k_map; +std::map bc_pad_map; + +/************************************************* +* Alias to canonical name mapping table * +*************************************************/ +std::map alias_map; + +/************************************************* +* Mutexes controlling access to the tables * +*************************************************/ +Mutex* s2k_map_lock = 0; +Mutex* bc_pad_map_lock = 0; +Mutex* alias_map_lock = 0; + +} + +/************************************************* +* Retrieve a S2K algorithm * +*************************************************/ +const S2K* retrieve_s2k(const std::string& name) + { + S2K* retval = 0; + s2k_map_lock->lock(); + std::map::const_iterator algo; + algo = s2k_map.find(deref_alias(name)); + if(algo != s2k_map.end()) + retval = algo->second; + s2k_map_lock->unlock(); + if(!retval) + { + retval = Algolist::get_s2k(deref_alias(name)); + add_algorithm(retval); + } + return retval; + } + +/************************************************* +* Retrieve a block cipher padding method * +*************************************************/ +const BlockCipherModePaddingMethod* retrieve_bc_pad(const std::string& name) + { + BlockCipherModePaddingMethod* retval = 0; + bc_pad_map_lock->lock(); + std::map::const_iterator algo; + algo = bc_pad_map.find(deref_alias(name)); + if(algo != bc_pad_map.end()) + retval = algo->second; + bc_pad_map_lock->unlock(); + if(!retval) + { + retval = Algolist::get_bc_pad(deref_alias(name)); + add_algorithm(retval); + } + return retval; + } + +/************************************************* +* Add a S2K algorithm to the lookup table * +*************************************************/ +void add_algorithm(S2K* algo) + { + if(!algo) return; + s2k_map_lock->lock(); + if(s2k_map.find(algo->name()) != s2k_map.end()) + delete s2k_map[algo->name()]; + s2k_map[algo->name()] = algo; + s2k_map_lock->unlock(); + } + +/************************************************* +* Add a padding method to the lookup table * +*************************************************/ +void add_algorithm(BlockCipherModePaddingMethod* algo) + { + if(!algo) return; + bc_pad_map_lock->lock(); + if(bc_pad_map.find(algo->name()) != bc_pad_map.end()) + delete bc_pad_map[algo->name()]; + bc_pad_map[algo->name()] = algo; + bc_pad_map_lock->unlock(); + } + +/************************************************* +* Add an alias for an algorithm * +*************************************************/ +void add_alias(const std::string& alias, const std::string& official_name) + { + if(alias == "" || official_name == "") + return; + + Mutex_Holder lock(alias_map_lock); + + if(alias_map.find(alias) != alias_map.end()) + { + if(deref_alias(alias_map[alias]) != deref_alias(official_name)) + throw Invalid_Argument("add_alias: The alias " + alias + + " already exists"); + return; + } + + alias_map[alias] = official_name; + } + +/************************************************* +* Dereference an alias * +*************************************************/ +std::string deref_alias(const std::string& name) + { + std::map::const_iterator realname; + realname = alias_map.find(name); + if(realname == alias_map.end()) + return name; + return deref_alias(realname->second); + } + +/************************************************* +* Handle startup for the lookup tables * +*************************************************/ +void init_lookup_tables() + { + s2k_map_lock = get_mutex(); + bc_pad_map_lock = get_mutex(); + alias_map_lock = get_mutex(); + } + +/************************************************* +* Destroy the lookup tables * +*************************************************/ +void destroy_lookup_tables() + { + std::map::iterator s2k_iter; + for(s2k_iter = s2k_map.begin(); s2k_iter != s2k_map.end(); s2k_iter++) + delete s2k_iter->second; + + std::map::iterator pad_iter; + for(pad_iter = bc_pad_map.begin(); pad_iter != bc_pad_map.end(); pad_iter++) + delete pad_iter->second; + + s2k_map.clear(); + bc_pad_map.clear(); + alias_map.clear(); + + delete s2k_map_lock; + delete bc_pad_map_lock; + delete alias_map_lock; + + s2k_map_lock = 0; + bc_pad_map_lock = 0; + alias_map_lock = 0; + } + +} --- botan/lookup.h +++ botan/lookup.h @@ -0,0 +1,81 @@ +/************************************************* +* Algorithm Lookup Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_LOOKUP_H__ +#define BOTAN_LOOKUP_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Retrieve an object from the lookup table * +*************************************************/ +const BlockCipher* retrieve_block_cipher(const std::string&); +const StreamCipher* retrieve_stream_cipher(const std::string&); +const HashFunction* retrieve_hash(const std::string&); +const MessageAuthenticationCode* retrieve_mac(const std::string&); +const S2K* retrieve_s2k(const std::string&); +const BlockCipherModePaddingMethod* retrieve_bc_pad(const std::string&); + +/************************************************* +* Get an algorithm object * +*************************************************/ +BlockCipher* get_block_cipher(const std::string&); +StreamCipher* get_stream_cipher(const std::string&); +HashFunction* get_hash(const std::string&); +MessageAuthenticationCode* get_mac(const std::string&); +S2K* get_s2k(const std::string&); +const BlockCipherModePaddingMethod* get_bc_pad(const std::string&); + +/************************************************* +* Get an EMSA/EME/KDF/MGF function * +*************************************************/ +EME* get_eme(const std::string&); +EMSA* get_emsa(const std::string&); +MGF* get_mgf(const std::string&); +KDF* get_kdf(const std::string&); + +/************************************************* +* Get a cipher object * +*************************************************/ +Keyed_Filter* get_cipher(const std::string&, const SymmetricKey&, + const InitializationVector&, Cipher_Dir); +Keyed_Filter* get_cipher(const std::string&, const SymmetricKey&, Cipher_Dir); +Keyed_Filter* get_cipher(const std::string&, Cipher_Dir); + +/************************************************* +* Check to see if an algorithm exists * +*************************************************/ +bool have_algorithm(const std::string&); + +bool have_block_cipher(const std::string&); +bool have_stream_cipher(const std::string&); +bool have_hash(const std::string&); +bool have_mac(const std::string&); + +/************************************************* +* Dereference an alias * +*************************************************/ +std::string deref_alias(const std::string&); + +/************************************************* +* Query information about an algorithm * +*************************************************/ +u32bit block_size_of(const std::string&); +u32bit output_length_of(const std::string&); + +bool valid_keylength_for(u32bit, const std::string&); +u32bit min_keylength_of(const std::string&); +u32bit max_keylength_of(const std::string&); +u32bit keylength_multiple_of(const std::string&); + +} + +#endif --- botan/make_prm.cpp +++ botan/make_prm.cpp @@ -0,0 +1,174 @@ +/************************************************* +* Prime Generation Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Increment the seed by one * +*************************************************/ +void increment(SecureVector& seed) + { + for(u32bit j = seed.size(); j > 0; j--) + if(++seed[j-1]) + break; + } + +} + +/************************************************* +* Attempt DSA prime generation with given seed * +*************************************************/ +bool generate_dsa_primes(BigInt& p, BigInt& q, const byte const_seed[], + u32bit seed_len, u32bit pbits, u32bit counter_start) + { + if(seed_len < 20) + throw Invalid_Argument("DSA prime generation needs a seed " + "at least 160 bits long"); + if((pbits % 64 != 0) || (pbits > 1024) || (pbits < 512)) + throw Invalid_Argument("DSA prime generation algorithm does not support " + "prime size " + to_string(pbits)); + + std::auto_ptr sha1(get_hash("SHA-1")); + + SecureVector seed(const_seed, seed_len); + + SecureVector qhash = sha1->process(seed); + increment(seed); + SecureVector qhash2 = sha1->process(seed); + xor_buf(qhash, qhash2, qhash.size()); + + qhash[0] |= 0x80; + qhash[19] |= 0x01; + q.binary_decode(qhash, qhash.size()); + if(!is_prime(q)) + return false; + UI::pulse(UI::PRIME_FOUND); + + u32bit n = (pbits-1) / 160, b = (pbits-1) % 160; + SecureVector W(20 * (n+1)); + BigInt X; + + for(u32bit j = 0; j != counter_start; j++) + for(u32bit k = 0; k != n + 1; k++) + increment(seed); + + for(u32bit j = 0; j != 4096 - counter_start; j++) + { + UI::pulse(UI::PRIME_SEARCHING); + + for(u32bit k = 0; k != n + 1; k++) + { + increment(seed); + sha1->update(seed); + sha1->final(W + 20 * (n-k)); + } + X.binary_decode(W + (20 - 1 - b/8), W.size() - (20 - 1 - b/8)); + X.set_bit(pbits-1); + + p = X - (X % (2*q) - 1); + + if(p.bits() == pbits && is_prime(p)) + { + UI::pulse(UI::PRIME_FOUND); + return true; + } + } + return false; + } + +/************************************************* +* Generate DSA Primes * +*************************************************/ +SecureVector generate_dsa_primes(BigInt& p, BigInt& q, u32bit pbits) + { + SecureVector seed(20); + + while(true) + { + Global_RNG::randomize(seed, seed.size(), Nonce); + UI::pulse(UI::PRIME_SEARCHING); + if(generate_dsa_primes(p, q, seed, seed.size(), pbits)) + return seed; + } + } + +/************************************************* +* Generate a random prime * +*************************************************/ +BigInt random_prime(u32bit bits, RNG_Quality level, const BigInt& coprime, + u32bit equiv, u32bit modulo) + { + if(bits <= 48) + throw Invalid_Argument("random_prime: Can't make a prime of " + + to_string(bits) + " bits"); + + 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) + { + UI::pulse(UI::PRIME_SEARCHING); + + BigInt p = random_integer(bits, level); + p.set_bit(bits - 2); + p.set_bit(0); + + if(p % modulo != equiv) + p += (modulo - p % modulo) + equiv; + + const u32bit sieve_size = std::min(bits / 2, PRIME_TABLE_SIZE); + SecureVector sieve(sieve_size); + + for(u32bit j = 0; j != sieve.size(); j++) + { + sieve[j] = p % PRIMES[j]; + UI::pulse(UI::PRIME_SIEVING); + } + + u32bit counter = 0; + while(true) + { + if(counter == 4096 || p.bits() > bits) + break; + + UI::pulse(UI::PRIME_SEARCHING); + + bool passes_sieve = true; + counter++; + p += modulo; + + for(u32bit j = 0; j != sieve.size(); j++) + { + sieve[j] = (sieve[j] + modulo) % PRIMES[j]; + UI::pulse(UI::PRIME_SIEVING); + if(sieve[j] == 0) + passes_sieve = false; + } + + if(!passes_sieve || gcd(p - 1, coprime) != 1) + continue; + UI::pulse(UI::PRIME_PASSED_SIEVE); + if(passes_mr_tests(p)) + { + UI::pulse(UI::PRIME_FOUND); + return p; + } + } + } + } + +} --- botan/mdx_hash.cpp +++ botan/mdx_hash.cpp @@ -0,0 +1,91 @@ +/************************************************* +* MDx Hash Function Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* MDx_HashFunction Constructor * +*************************************************/ +MDx_HashFunction::MDx_HashFunction(u32bit hash_len, u32bit block_len, + bool byte_end, bool bit_end, + u32bit cnt_size) : + HashFunction(hash_len, block_len), buffer(block_len), + BIG_BYTE_ENDIAN(byte_end), BIG_BIT_ENDIAN(bit_end), COUNT_SIZE(cnt_size) + { + if(COUNT_SIZE >= OUTPUT_LENGTH || COUNT_SIZE >= HASH_BLOCK_SIZE) + throw Invalid_Argument("MDx_HashFunction: COUNT_SIZE is too big"); + count = position = 0; + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void MDx_HashFunction::clear() throw() + { + buffer.clear(); + count = position = 0; + } + +/************************************************* +* Update the hash * +*************************************************/ +void MDx_HashFunction::add_data(const byte input[], u32bit length) + { + count += length; + buffer.copy(position, input, length); + if(position + length >= HASH_BLOCK_SIZE) + { + hash(buffer.begin()); + 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; + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/************************************************* +* Finalize a Hash * +*************************************************/ +void MDx_HashFunction::final_result(byte output[]) + { + buffer[position] = (BIG_BIT_ENDIAN ? 0x80 : 0x01); + for(u32bit j = position+1; j != HASH_BLOCK_SIZE; j++) + buffer[j] = 0; + if(position >= HASH_BLOCK_SIZE - COUNT_SIZE) + { + hash(buffer); + buffer.clear(); + } + write_count(buffer + HASH_BLOCK_SIZE - COUNT_SIZE); + + hash(buffer); + copy_out(output); + clear(); + } + +/************************************************* +* Write the count bits to the buffer * +*************************************************/ +void MDx_HashFunction::write_count(byte buffer[]) + { + if(COUNT_SIZE < 8) + throw Invalid_State("MDx_HashFunction::write_count: COUNT_SIZE < 8"); + for(u32bit j = 0; j != 8; j++) + { + const u32bit choose = (BIG_BYTE_ENDIAN ? (j % 8) : (7 - (j % 8))); + buffer[j+COUNT_SIZE-8] = get_byte(choose, 8 * count); + } + } + +} --- botan/mdx_hash.h +++ botan/mdx_hash.h @@ -0,0 +1,40 @@ +/************************************************* +* MDx Hash Function Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MDX_BASE_H__ +#define BOTAN_MDX_BASE_H__ + +#include + +namespace Botan { + +/************************************************* +* MDx Hash Function Base Class * +*************************************************/ +class MDx_HashFunction : public HashFunction + { + public: + MDx_HashFunction(u32bit, u32bit, bool, bool, u32bit = 8); + virtual ~MDx_HashFunction() {} + protected: + void clear() throw(); + SecureVector buffer; + u64bit count; + u32bit position; + private: + void add_data(const byte[], u32bit); + void final_result(byte output[]); + + virtual void hash(const byte[]) = 0; + virtual void copy_out(byte[]) = 0; + virtual void write_count(byte[]); + + const bool BIG_BYTE_ENDIAN, BIG_BIT_ENDIAN; + const u32bit COUNT_SIZE; + }; + +} + +#endif --- botan/mem_ops.h +++ botan/mem_ops.h @@ -0,0 +1,31 @@ +/************************************************* +* Memory Operations Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MEMORY_OPS_H__ +#define BOTAN_MEMORY_OPS_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Memory Manipulation Functions * +*************************************************/ +template inline void copy_mem(T* out, const T* in, u32bit n) + { std::memmove(out, in, sizeof(T)*n); } + +template inline void clear_mem(T* ptr, u32bit n) + { std::memset(ptr, 0, sizeof(T)*n); } + +template inline void set_mem(T* ptr, u32bit n, byte val) + { std::memset(ptr, val, sizeof(T)*n); } + +template inline bool same_mem(const T* p1, const T* p2, u32bit n) + { return (cmp_mem(p1, p2, n) == 0); } + +} + +#endif --- botan/mem_pool.cpp +++ botan/mem_pool.cpp @@ -0,0 +1,373 @@ +/************************************************* +* Pooling Allocator Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Buffer Comparison Operators * +*************************************************/ +bool Buffer_Cmp(const Pooling_Allocator::Buffer& a, + const Pooling_Allocator::Buffer& b) + { return ((const byte*)a.buf < (const byte*)b.buf); } + +bool Empty_Buffer(const Pooling_Allocator::Buffer& block) + { return (block.length == 0); } + +} + +/************************************************* +* Pooling_Allocator Constructor * +*************************************************/ +Pooling_Allocator::Pooling_Allocator(u32bit size) : + PREF_SIZE(size ? size : Config::get_u32bit("base/memory_chunk")), + ALIGN_TO(16) + { + if(PREF_SIZE == 0) + throw Internal_Error("The base/memory_chunk option is unset"); + lock = get_mutex(); + initialized = destroyed = false; + defrag_counter = 0; + } + +/************************************************* +* Pooling_Allocator Destructor * +*************************************************/ +Pooling_Allocator::~Pooling_Allocator() + { + delete lock; + if(!initialized) + throw Invalid_State("Pooling_Allocator: Was never initialized"); + if(!destroyed) + throw Invalid_State("Pooling_Allocator: Never released memory"); + } + +/************************************************* +* Allocate some initial buffers * +*************************************************/ +void Pooling_Allocator::init() + { + if(PREF_SIZE >= 64 && prealloc_bytes()) + { + u32bit allocated = 0; + while(allocated < prealloc_bytes()) + { + void* ptr = 0; + try { + ptr = alloc_block(PREF_SIZE); + allocated += PREF_SIZE; + } + catch(Exception) {} + + if(!ptr) + break; + + real_mem.push_back(Buffer(ptr, PREF_SIZE, false)); + } + } + + initialized = true; + } + +/************************************************* +* Free all remaining memory * +*************************************************/ +void Pooling_Allocator::destroy() + { + if(!initialized) + throw Invalid_State("Pooling_Allocator::destroy(): Never initialized"); + if(destroyed) + throw Invalid_State("Pooling_Allocator::destroy(): Already destroyed"); + + destroyed = true; + for(u32bit j = 0; j != real_mem.size(); j++) + dealloc_block(real_mem[j].buf, real_mem[j].length); + } + +/************************************************* +* Return true if these buffers are contiguous * +*************************************************/ +bool Pooling_Allocator::are_contiguous(const Buffer& a, const Buffer& b) + { + if((const byte*)a.buf + a.length == (const byte*)b.buf) + return true; + return false; + } + +/************************************************* +* See if two free blocks are from the same block * +*************************************************/ +bool Pooling_Allocator::same_buffer(Buffer& a, Buffer& b) const + { + return (find_block(a.buf) == find_block(b.buf)); + } + +/************************************************* +* Find the block containing this memory * +*************************************************/ +u32bit Pooling_Allocator::find_block(void* addr) const + { + for(u32bit j = 0; j != real_mem.size(); j++) + { + const byte* buf_addr = (const byte*)real_mem[j].buf; + if(buf_addr <= (byte*)addr && + (byte*)addr < buf_addr + real_mem[j].length) + return j; + } + throw Internal_Error("Pooling_Allocator::find_block: no buffer found"); + } + +/************************************************* +* Remove empty buffers from list * +*************************************************/ +void Pooling_Allocator::remove_empty_buffers(std::vector& list) const + { + std::vector::iterator empty; + + empty = std::find_if(list.begin(), list.end(), Empty_Buffer); + while(empty != list.end()) + { + list.erase(empty); + empty = std::find_if(list.begin(), list.end(), Empty_Buffer); + } + } + +/************************************************* +* Allocation * +*************************************************/ +void* Pooling_Allocator::allocate(u32bit n) const + { + struct Memory_Exhaustion : public Exception + { + Memory_Exhaustion() : + Exception("Pooling_Allocator: Ran out of memory") {} + }; + + if(n == 0) return 0; + n = round_up(n, ALIGN_TO); + + Mutex_Holder holder(lock); + + void* new_buf = find_free_block(n); + if(new_buf) + return alloc_hook(new_buf, n); + + Buffer block; + block.length = ((n > PREF_SIZE) ? n : PREF_SIZE); + block.buf = get_block(block.length); + if(!block.buf) + throw Memory_Exhaustion(); + free_list.push_back(block); + + new_buf = find_free_block(n); + if(new_buf) + return alloc_hook(new_buf, n); + + throw Memory_Exhaustion(); + } + +/************************************************* +* Deallocation * +*************************************************/ +void Pooling_Allocator::deallocate(void* ptr, u32bit n) const + { + const u32bit RUNS_TO_DEFRAGS = 16; + + if(ptr == 0 || n == 0) return; + + n = round_up(n, ALIGN_TO); + std::memset(ptr, 0, n); + + Mutex_Holder holder(lock); + + dealloc_hook(ptr, n); + + free_list.push_back(Buffer(ptr, n)); + if(free_list.size() >= 2) + std::inplace_merge(free_list.begin(), free_list.end() - 1, + free_list.end(), Buffer_Cmp); + + defrag_counter = (defrag_counter + 1) % RUNS_TO_DEFRAGS; + if(defrag_counter == 0) + { + for(u32bit j = 0; j != free_list.size(); j++) + { + bool erase = false; + if(free_list[j].buf == 0) continue; + + for(u32bit k = 0; k != real_mem.size(); k++) + if(free_list[j].buf == real_mem[k].buf && + free_list[j].length == real_mem[k].length) + erase = true; + + if(erase) + { + const u32bit buf = find_block(free_list[j].buf); + free_block(real_mem[buf].buf, real_mem[buf].length); + free_list[j].buf = 0; + free_list[j].length = 0; + } + } + + defrag_free_list(); + } + } + +/************************************************* +* Handle Allocating New Memory * +*************************************************/ +void* Pooling_Allocator::get_block(u32bit n) const + { + for(u32bit j = 0; j != real_mem.size(); j++) + if(!real_mem[j].in_use && real_mem[j].length == n) + { + real_mem[j].in_use = true; + return real_mem[j].buf; + } + + void* ptr = 0; + try { + ptr = alloc_block(n); + } + catch(Exception) {} + + if(ptr) + real_mem.push_back(Buffer(ptr, n, true)); + return ptr; + } + +/************************************************* +* Handle Deallocating Memory * +*************************************************/ +void Pooling_Allocator::free_block(void* ptr, u32bit n) const + { + if(!ptr) return; + + u32bit free_blocks = 0; + for(u32bit j = 0; j != real_mem.size(); j++) + if(!real_mem[j].in_use) free_blocks++; + + bool free_this_block = false; + if((free_blocks > 2 || n != PREF_SIZE) && !should_not_free()) + free_this_block = true; + + for(u32bit j = 0; j != real_mem.size(); j++) + if(real_mem[j].buf == ptr) + { + if(!real_mem[j].in_use || real_mem[j].length != n) + throw Internal_Error("Pooling_Allocator: Size mismatch in free"); + + if(free_this_block) + { + dealloc_block(real_mem[j].buf, real_mem[j].length); + real_mem[j].buf = 0; + real_mem[j].length = 0; + } + else + real_mem[j].in_use = false; + + return; + } + + remove_empty_buffers(real_mem); + + throw Internal_Error("Pooling_Allocator: Unknown pointer was freed"); + } + +/************************************************* +* Defragment the free list * +*************************************************/ +void Pooling_Allocator::defrag_free_list() const + { + if(free_list.size() < 2) return; + + for(u32bit j = 0; j != free_list.size(); j++) + { + if(free_list[j].length == 0) + continue; + + if(j > 0 && + are_contiguous(free_list[j-1], free_list[j]) && + same_buffer(free_list[j-1], free_list[j])) + { + free_list[j].buf = free_list[j-1].buf; + free_list[j].length += free_list[j-1].length; + free_list[j-1].length = 0; + } + + if(j < free_list.size() - 1 && + are_contiguous(free_list[j], free_list[j+1]) && + same_buffer(free_list[j], free_list[j+1])) + { + free_list[j+1].buf = free_list[j].buf; + free_list[j+1].length += free_list[j].length; + free_list[j].length = 0; + } + } + remove_empty_buffers(free_list); + } + +/************************************************* +* Find a block on the free list * +*************************************************/ +void* Pooling_Allocator::find_free_block(u32bit n) const + { + void* retval = 0; + + for(u32bit j = 0; j != free_list.size(); j++) + if(free_list[j].length >= n) + { + retval = free_list[j].buf; + + if(free_list[j].length == n) + free_list.erase(free_list.begin() + j); + else if(free_list[j].length > n) + { + free_list[j].length -= n; + free_list[j].buf = ((byte*)free_list[j].buf) + n; + } + break; + } + + return retval; + } + +/************************************************* +* Allocation hook for debugging * +*************************************************/ +void* Pooling_Allocator::alloc_hook(void* ptr, u32bit) const + { + return ptr; + } + +/************************************************* +* Deallocation hook for debugging * +*************************************************/ +void Pooling_Allocator::dealloc_hook(void*, u32bit) const + { + } + +/************************************************* +* Run internal consistency checks * +*************************************************/ +void Pooling_Allocator::consistency_check() const + { + for(u32bit j = 0; j != free_list.size(); j++) + { + const byte* byte_buf = (const byte*)free_list[j].buf; + const u32bit length = free_list[j].length; + + for(u32bit k = 0; k != length; k++) + if(byte_buf[k]) + throw Internal_Error("Pooling_Allocator: free list corrupted"); + } + } + +} --- botan/mem_pool.h +++ botan/mem_pool.h @@ -0,0 +1,71 @@ +/************************************************* +* Pooling Allocator Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_POOLING_ALLOCATOR_H__ +#define BOTAN_POOLING_ALLOCATOR_H__ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Pooling Allocator * +*************************************************/ +class Pooling_Allocator : public Allocator + { + public: + class Buffer + { + public: + void* buf; + u32bit length; + bool in_use; + Buffer() { buf = 0; length = 0; in_use = false; } + Buffer(void* b, u32bit l, bool used = false) + { buf = b; length = l; in_use = used; } + }; + + void* allocate(u32bit) const; + void deallocate(void*, u32bit) const; + + void init(); + void destroy(); + + Pooling_Allocator(u32bit = 0); + ~Pooling_Allocator(); + private: + void* get_block(u32bit) const; + void free_block(void*, u32bit) const; + + virtual void* alloc_block(u32bit) const = 0; + virtual void dealloc_block(void*, u32bit) const = 0; + virtual u32bit prealloc_bytes() const { return 0; } + virtual bool should_not_free() const { return false; } + + void* alloc_hook(void*, u32bit) const; + void dealloc_hook(void*, u32bit) const; + void consistency_check() const; + + void* find_free_block(u32bit) const; + void defrag_free_list() const; + + static bool are_contiguous(const Buffer&, const Buffer&); + u32bit find_block(void*) const; + bool same_buffer(Buffer&, Buffer&) const; + void remove_empty_buffers(std::vector&) const; + + const u32bit PREF_SIZE, ALIGN_TO; + mutable std::vector real_mem, free_list; + mutable Mutex* lock; + mutable u32bit defrag_counter; + bool initialized, destroyed; + }; + +} + +#endif --- botan/mgf1.cpp +++ botan/mgf1.cpp @@ -0,0 +1,47 @@ +/************************************************* +* MGF1 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* MGF1 Mask Generation Function * +*************************************************/ +void MGF1::mask(const byte in[], u32bit in_len, byte out[], + u32bit out_len) const + { + u32bit counter = 0; + + std::auto_ptr hash(get_hash(hash_name)); + + while(out_len) + { + hash->update(in, in_len); + for(u32bit j = 0; j != 4; j++) + hash->update(get_byte(j, counter)); + SecureVector buffer = hash->final(); + + u32bit xored = std::min(buffer.size(), out_len); + xor_buf(out, buffer.begin(), xored); + out += xored; + out_len -= xored; + + counter++; + } + } + +/************************************************* +* MGF1 Constructor * +*************************************************/ +MGF1::MGF1(const std::string& h_name) : hash_name(h_name) + { + if(!have_hash(hash_name)) + throw Algorithm_Not_Found(hash_name); + } + +} --- botan/mgf1.h +++ botan/mgf1.h @@ -0,0 +1,27 @@ +/************************************************* +* MGF1 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MGF1_H__ +#define BOTAN_MGF1_H__ + +#include + +namespace Botan { + +/************************************************* +* MGF1 * +*************************************************/ +class MGF1 : public MGF + { + public: + void mask(const byte[], u32bit, byte[], u32bit) const; + MGF1(const std::string&); + private: + const std::string hash_name; + }; + +} + +#endif --- botan/mlock.cpp +++ botan/mlock.cpp @@ -0,0 +1,24 @@ +/************************************************* +* Memory Locking Functions Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Lock an area of memory into RAM * +*************************************************/ +void lock_mem(void*, u32bit) + { + } + +/************************************************* +* Unlock a previously locked region of memory * +*************************************************/ +void unlock_mem(void*, u32bit) + { + } + +} --- botan/mod_exp.cpp +++ botan/mod_exp.cpp @@ -0,0 +1,208 @@ +/************************************************* +* Modular Exponentiation Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* FixedExponent_Exp Constructor * +*************************************************/ +FixedExponent_Exp::FixedExponent_Exp(const BigInt& exp, const BigInt& mod) : + reducer(get_reducer(mod)), exponent(exp) + { + if(mod <= 0) + throw Invalid_Argument("FixedExponent_Exp: Invalid modulus"); + if(exp < 0) + throw Invalid_Argument("FixedExponent_Exp: Invalid exponent"); + } + +/************************************************* +* FixedExponent_Exp Copy Constructor * +*************************************************/ +FixedExponent_Exp::FixedExponent_Exp(const FixedExponent_Exp& exp) + { + exponent = 0; + reducer = 0; + + if(exp.initialized()) + { + exponent = exp.get_exponent(); + reducer = get_reducer(exp.get_modulus()); + } + } + +/************************************************* +* FixedExponent_Exp Assignment Operator * +*************************************************/ +FixedExponent_Exp& FixedExponent_Exp::operator=(const FixedExponent_Exp& exp) + { + delete reducer; + exponent = 0; + reducer = 0; + + if(exp.initialized()) + { + reducer = get_reducer(exp.get_modulus()); + exponent = exp.get_exponent(); + } + return (*this); + } + +/************************************************* +* Fixed Exponent Exponentiation * +*************************************************/ +BigInt FixedExponent_Exp::power_mod(const BigInt& base) const + { + init_check(); + return Botan::power_mod(reducer->reduce(base), exponent, reducer); + } + +/************************************************* +* Calculate n modulo the fixed modulus * +*************************************************/ +BigInt FixedExponent_Exp::reduce(const BigInt& n) const + { + init_check(); + return reducer->reduce(n); + } + +/************************************************* +* Return the exponent being used * +*************************************************/ +const BigInt& FixedExponent_Exp::get_exponent() const + { + init_check(); + return exponent; + } + +/************************************************* +* Return the modulus being used * +*************************************************/ +const BigInt& FixedExponent_Exp::get_modulus() const + { + init_check(); + return reducer->get_modulus(); + } + +/************************************************* +* Ensure the object has been initialized * +*************************************************/ +void FixedExponent_Exp::init_check() const + { + if(!initialized()) + throw Invalid_State("FixedExponent_Exp: Uninitialized access"); + } + +/************************************************* +* FixedBase_Exp Constructor * +*************************************************/ +FixedBase_Exp::FixedBase_Exp(const BigInt& base, const BigInt& mod) : + reducer(get_reducer(mod)), g(255) + { + if(mod <= 0) + throw Invalid_Argument("FixedBase_Exp: Invalid modulus"); + if(base < 0) + throw Invalid_Argument("FixedBase_Exp: Invalid base"); + + g[0] = base; + for(u32bit j = 1; j != g.size(); j++) + g[j] = reducer->multiply(g[j-1], g[0]); + } + +/************************************************* +* FixedBase_Exp Copy Constructor * +*************************************************/ +FixedBase_Exp::FixedBase_Exp(const FixedBase_Exp& exp) + { + reducer = 0; + + if(exp.initialized()) + { + reducer = get_reducer(exp.get_modulus()); + g = exp.g; + } + } + +/************************************************* +* FixedBase_Exp Assignment Operator * +*************************************************/ +FixedBase_Exp& FixedBase_Exp::operator=(const FixedBase_Exp& exp) + { + delete reducer; + reducer = 0; + + if(exp.initialized()) + { + reducer = get_reducer(exp.get_modulus()); + g = exp.g; + } + return (*this); + } + +/************************************************* +* Fixed Base Exponentiation * +*************************************************/ +BigInt FixedBase_Exp::power_mod(const BigInt& exp) const + { + init_check(); + if(exp.is_negative()) + throw Invalid_Argument("power_mod: exponent must be positive"); + if(exp.is_zero()) + return 1; + + const u32bit exp_bytes = (exp.bits() + 7) / 8; + + BigInt x = 1; + for(u32bit j = exp_bytes; j > 0; j--) + { + for(u32bit k = 0; k != 8; k++) + x = reducer->square(x); + u32bit nibble = exp.byte_at(j-1); + if(nibble) + x = reducer->multiply(x, g[nibble-1]); + } + return x; + } + +/************************************************* +* Calculate n modulo the fixed modulus * +*************************************************/ +BigInt FixedBase_Exp::reduce(const BigInt& n) const + { + init_check(); + return reducer->reduce(n); + } + +/************************************************* +* Return the generator being used * +*************************************************/ +const BigInt& FixedBase_Exp::get_base() const + { + init_check(); + return g[0]; + } + +/************************************************* +* Return the modulus being used * +*************************************************/ +const BigInt& FixedBase_Exp::get_modulus() const + { + init_check(); + return reducer->get_modulus(); + } + +/************************************************* +* Ensure the object has been initialized * +*************************************************/ +void FixedBase_Exp::init_check() const + { + if(!initialized()) + throw Invalid_State("FixedBase_Exp: Uninitialized access"); + } + + +} --- botan/mod_exp.h +++ botan/mod_exp.h @@ -0,0 +1,71 @@ +/************************************************* +* Modular Exponentiation Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MODULAR_EXP_H__ +#define BOTAN_MODULAR_EXP_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Fixed Exponent Exponentiation * +*************************************************/ +class FixedExponent_Exp + { + public: + BigInt operator() (const BigInt& n) const { return power_mod(n); } + BigInt reduce(const BigInt&) const; + BigInt power_mod(const BigInt&) const; + + const BigInt& get_exponent() const; + const BigInt& get_modulus() const; + + bool initialized() const { return (reducer != 0); } + + FixedExponent_Exp& operator=(const FixedExponent_Exp&); + + FixedExponent_Exp() { reducer = 0; } + FixedExponent_Exp(const BigInt&, const BigInt&); + FixedExponent_Exp(const FixedExponent_Exp&); + ~FixedExponent_Exp() { delete reducer; } + private: + void init_check() const; + ModularReducer* reducer; + BigInt exponent; + }; + +/************************************************* +* Fixed Base Exponentiation * +*************************************************/ +class FixedBase_Exp + { + public: + BigInt operator() (const BigInt& n) const { return power_mod(n); } + BigInt reduce(const BigInt& n) const; + BigInt power_mod(const BigInt&) const; + + const BigInt& get_base() const; + const BigInt& get_modulus() const; + + bool initialized() const { return (reducer != 0); } + + FixedBase_Exp& operator=(const FixedBase_Exp&); + + FixedBase_Exp() { reducer = 0; } + FixedBase_Exp(const BigInt&, const BigInt&); + FixedBase_Exp(const FixedBase_Exp&); + ~FixedBase_Exp() { delete reducer; } + private: + void init_check() const; + ModularReducer* reducer; + std::vector g; + }; + +} + +#endif --- botan/mode_pad.cpp +++ botan/mode_pad.cpp @@ -0,0 +1,125 @@ +/************************************************* +* CBC Padding Methods Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Default amount of padding * +*************************************************/ +u32bit BlockCipherModePaddingMethod::pad_bytes(u32bit bs, u32bit pos) const + { + return (bs - pos); + } + +/************************************************* +* Pad with PKCS #7 Method * +*************************************************/ +void PKCS7_Padding::pad(byte block[], u32bit size, u32bit position) const + { + for(u32bit j = 0; j != size; j++) + block[j] = (size-position); + } + +/************************************************* +* Unpad with PKCS #7 Method * +*************************************************/ +u32bit PKCS7_Padding::unpad(const byte block[], u32bit size) const + { + u32bit position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(u32bit j = size-position; j != size-1; j++) + if(block[j] != position) + throw Decoding_Error(name()); + return (size-position); + } + +/************************************************* +* Query if the size is valid for this method * +*************************************************/ +bool PKCS7_Padding::valid_blocksize(u32bit size) const + { + if(size > 0 && size < 256) + return true; + else + return false; + } + +/************************************************* +* Pad with ANSI X9.23 Method * +*************************************************/ +void ANSI_X923_Padding::pad(byte block[], u32bit size, u32bit position) const + { + for(u32bit j = 0; j != size-position; j++) + block[j] = 0; + block[size-position-1] = (size-position); + } + +/************************************************* +* Unpad with ANSI X9.23 Method * +*************************************************/ +u32bit ANSI_X923_Padding::unpad(const byte block[], u32bit size) const + { + u32bit position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(u32bit j = size-position; j != size-1; j++) + if(block[j] != 0) + throw Decoding_Error(name()); + return (size-position); + } + +/************************************************* +* Query if the size is valid for this method * +*************************************************/ +bool ANSI_X923_Padding::valid_blocksize(u32bit size) const + { + if(size > 0 && size < 256) + return true; + else + return false; + } + +/************************************************* +* Pad with One and Zeros Method * +*************************************************/ +void OneAndZeros_Padding::pad(byte block[], u32bit size, u32bit) const + { + block[0] = 0x80; + for(u32bit j = 1; j != size; j++) + block[j] = 0x00; + } + +/************************************************* +* Unpad with One and Zeros Method * +*************************************************/ +u32bit OneAndZeros_Padding::unpad(const byte block[], u32bit 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); + } + +/************************************************* +* Query if the size is valid for this method * +*************************************************/ +bool OneAndZeros_Padding::valid_blocksize(u32bit size) const + { + if(size) return true; + else return false; + } + +} --- botan/mode_pad.h +++ botan/mode_pad.h @@ -0,0 +1,78 @@ +/************************************************* +* CBC Padding Methods Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CBC_PADDING_H__ +#define BOTAN_CBC_PADDING_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Block Cipher Mode Padding Method * +*************************************************/ +class BlockCipherModePaddingMethod + { + public: + virtual void pad(byte[], u32bit, u32bit) const = 0; + virtual u32bit unpad(const byte[], u32bit) const = 0; + virtual u32bit pad_bytes(u32bit, u32bit) const; + virtual bool valid_blocksize(u32bit) const = 0; + virtual std::string name() const = 0; + }; + +/************************************************* +* PKCS#7 Padding * +*************************************************/ +class PKCS7_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const; + u32bit unpad(const byte[], u32bit) const; + bool valid_blocksize(u32bit) const; + std::string name() const { return "PKCS7"; } + }; + +/************************************************* +* ANSI X9.23 Padding * +*************************************************/ +class ANSI_X923_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const; + u32bit unpad(const byte[], u32bit) const; + bool valid_blocksize(u32bit) const; + std::string name() const { return "X9.23"; } + }; + +/************************************************* +* One And Zeros Padding * +*************************************************/ +class OneAndZeros_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const; + u32bit unpad(const byte[], u32bit) const; + bool valid_blocksize(u32bit) const; + std::string name() const { return "OneAndZeros"; } + }; + +/************************************************* +* Null Padding * +*************************************************/ +class Null_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const { return; } + u32bit unpad(const byte[], u32bit size) const { return size; } + u32bit pad_bytes(u32bit, u32bit) const { return 0; } + bool valid_blocksize(u32bit) const { return true; } + std::string name() const { return "NoPadding"; } + }; + +} + +#endif --- botan/modebase.cpp +++ botan/modebase.cpp @@ -0,0 +1,53 @@ +/************************************************* +* Block Cipher Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Block Cipher Mode Constructor * +*************************************************/ +BlockCipherMode::BlockCipherMode(const std::string& cipher_name, + const std::string& cipher_mode_name, + u32bit iv_size, u32bit iv_meth, + u32bit buf_mult) : + BLOCK_SIZE(block_size_of(cipher_name)), BUFFER_SIZE(buf_mult * BLOCK_SIZE), + IV_METHOD(iv_meth), mode_name(cipher_mode_name) + { + base_ptr = cipher = get_block_cipher(cipher_name); + buffer.create(BUFFER_SIZE); + state.create(iv_size); + position = 0; + } + +/************************************************* +* Return the name of this type * +*************************************************/ +std::string BlockCipherMode::name() const + { + return (cipher->name() + "/" + mode_name); + } + +/************************************************* +* Set the IV * +*************************************************/ +void BlockCipherMode::set_iv(const InitializationVector& new_iv) + { + if(new_iv.length() != state.size()) + throw Invalid_IV_Length(name(), new_iv.length()); + + state = new_iv.bits_of(); + buffer.clear(); + position = 0; + + if(IV_METHOD == 1) + cipher->encrypt(state, buffer); + else if(IV_METHOD == 2) + cipher->encrypt(state); + } + +} --- botan/modebase.h +++ botan/modebase.h @@ -0,0 +1,35 @@ +/************************************************* +* Block Cipher Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MODEBASE_H__ +#define BOTAN_MODEBASE_H__ + +#include + +namespace Botan { + +/************************************************* +* Block Cipher Mode * +*************************************************/ +class BlockCipherMode : public Keyed_Filter + { + public: + std::string name() const; + + BlockCipherMode(const std::string&, const std::string&, + u32bit, u32bit = 0, u32bit = 1); + virtual ~BlockCipherMode() { delete cipher; } + protected: + void set_iv(const InitializationVector&); + const u32bit BLOCK_SIZE, BUFFER_SIZE, IV_METHOD; + const std::string mode_name; + BlockCipher* cipher; + SecureVector buffer, state; + u32bit position; + }; + +} + +#endif --- botan/mp_comba.cpp +++ botan/mp_comba.cpp @@ -0,0 +1,235 @@ +/************************************************* +* Comba Multiplication Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Multiply-Add Accumulator * +*************************************************/ +void word3_muladd(word* w2, word* w1, word* w0, word x, word y) + { + word temp = 0; + bigint_madd(x, y, *w0, 0, w0, &temp); + *w1 += temp; + *w2 += (*w1 < temp) ? 1 : 0; + } + +} + +/************************************************* +* Comba 4x4 Multiplication * +*************************************************/ +void bigint_comba4(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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[1]); + word3_muladd(&w2, &w1, &w0, x[1], y[0]); + z[1] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[2]); + word3_muladd(&w2, &w1, &w0, x[1], y[1]); + word3_muladd(&w2, &w1, &w0, x[2], y[0]); + z[2] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[1], y[3]); + word3_muladd(&w2, &w1, &w0, x[2], y[2]); + word3_muladd(&w2, &w1, &w0, x[3], y[1]); + z[4] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[2], y[3]); + word3_muladd(&w2, &w1, &w0, x[3], y[2]); + z[5] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], y[3]); + z[6] = w0; + z[7] = w1; + } + +/************************************************* +* Comba 6x6 Multiplication * +*************************************************/ +void bigint_comba6(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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[1]); + word3_muladd(&w2, &w1, &w0, x[1], y[0]); + z[1] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[2]); + word3_muladd(&w2, &w1, &w0, x[1], y[1]); + word3_muladd(&w2, &w1, &w0, x[2], y[0]); + z[2] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[4]); + word3_muladd(&w2, &w1, &w0, x[1], y[3]); + word3_muladd(&w2, &w1, &w0, x[2], y[2]); + word3_muladd(&w2, &w1, &w0, x[3], y[1]); + word3_muladd(&w2, &w1, &w0, x[4], y[0]); + z[4] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[5]); + word3_muladd(&w2, &w1, &w0, x[1], y[4]); + word3_muladd(&w2, &w1, &w0, x[2], y[3]); + word3_muladd(&w2, &w1, &w0, x[3], y[2]); + word3_muladd(&w2, &w1, &w0, x[4], y[1]); + word3_muladd(&w2, &w1, &w0, x[5], y[0]); + z[5] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[2], y[5]); + word3_muladd(&w2, &w1, &w0, x[3], y[4]); + word3_muladd(&w2, &w1, &w0, x[4], y[3]); + word3_muladd(&w2, &w1, &w0, x[5], y[2]); + z[7] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], y[5]); + word3_muladd(&w2, &w1, &w0, x[4], y[4]); + word3_muladd(&w2, &w1, &w0, x[5], y[3]); + z[8] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[5], y[5]); + z[10] = w0; + z[11] = w1; + } + +/************************************************* +* Comba 8x8 Multiplication * +*************************************************/ +void bigint_comba8(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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[1]); + word3_muladd(&w2, &w1, &w0, x[1], y[0]); + z[1] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[2]); + word3_muladd(&w2, &w1, &w0, x[1], y[1]); + word3_muladd(&w2, &w1, &w0, x[2], y[0]); + z[2] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[4]); + word3_muladd(&w2, &w1, &w0, x[1], y[3]); + word3_muladd(&w2, &w1, &w0, x[2], y[2]); + word3_muladd(&w2, &w1, &w0, x[3], y[1]); + word3_muladd(&w2, &w1, &w0, x[4], y[0]); + z[4] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[5]); + word3_muladd(&w2, &w1, &w0, x[1], y[4]); + word3_muladd(&w2, &w1, &w0, x[2], y[3]); + word3_muladd(&w2, &w1, &w0, x[3], y[2]); + word3_muladd(&w2, &w1, &w0, x[4], y[1]); + word3_muladd(&w2, &w1, &w0, x[5], y[0]); + z[5] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[7]); + word3_muladd(&w2, &w1, &w0, x[1], y[6]); + word3_muladd(&w2, &w1, &w0, x[2], y[5]); + word3_muladd(&w2, &w1, &w0, x[3], y[4]); + word3_muladd(&w2, &w1, &w0, x[4], y[3]); + word3_muladd(&w2, &w1, &w0, x[5], y[2]); + word3_muladd(&w2, &w1, &w0, x[6], y[1]); + word3_muladd(&w2, &w1, &w0, x[7], y[0]); + z[7] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[1], y[7]); + word3_muladd(&w2, &w1, &w0, x[2], y[6]); + word3_muladd(&w2, &w1, &w0, x[3], y[5]); + word3_muladd(&w2, &w1, &w0, x[4], y[4]); + word3_muladd(&w2, &w1, &w0, x[5], y[3]); + word3_muladd(&w2, &w1, &w0, x[6], y[2]); + word3_muladd(&w2, &w1, &w0, x[7], y[1]); + z[8] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], y[7]); + word3_muladd(&w2, &w1, &w0, x[4], y[6]); + word3_muladd(&w2, &w1, &w0, x[5], y[5]); + word3_muladd(&w2, &w1, &w0, x[6], y[4]); + word3_muladd(&w2, &w1, &w0, x[7], y[3]); + z[10] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[4], y[7]); + word3_muladd(&w2, &w1, &w0, x[5], y[6]); + word3_muladd(&w2, &w1, &w0, x[6], y[5]); + word3_muladd(&w2, &w1, &w0, x[7], y[4]); + z[11] = w0; w0 = w1; w1 = 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 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[6], y[7]); + word3_muladd(&w2, &w1, &w0, x[7], y[6]); + z[13] = w0; w0 = w1; w1 = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[7], y[7]); + z[14] = w0; + z[15] = w1; + } + +} --- botan/mp_core.cpp +++ botan/mp_core.cpp @@ -0,0 +1,124 @@ +/************************************************* +* MPI Addition/Subtraction Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Two Operand Addition * +*************************************************/ +void bigint_add2(word x[], u32bit x_size, const word y[], u32bit y_size) + { + word carry = 0; + + for(u32bit j = 0; j != y_size; j++) + { + word z = x[j] + y[j] + carry; + + const u32bit top_x = x[j] >> (MP_WORD_BITS - 1); + const u32bit top_y = y[j] >> (MP_WORD_BITS - 1); + const u32bit top_z = z >> (MP_WORD_BITS - 1); + + x[j] = z; + carry = ((top_x | top_y) & !top_z) | (top_x & top_y); + } + + if(!carry) return; + + for(u32bit j = y_size; j != x_size; j++) + { + x[j]++; + if(x[j]) return; + } + x[x_size]++; + } + +/************************************************* +* Three Operand Addition * +*************************************************/ +void bigint_add3(word z[], const word x[], u32bit x_size, + const word y[], u32bit y_size) + { + if(x_size < y_size) + { bigint_add3(z, y, y_size, x, x_size); return; } + + word carry = 0; + for(u32bit j = 0; j != y_size; j++) + { + z[j] = x[j] + y[j] + carry; + + const u32bit top_x = x[j] >> (MP_WORD_BITS - 1); + const u32bit top_y = y[j] >> (MP_WORD_BITS - 1); + const u32bit top_z = z[j] >> (MP_WORD_BITS - 1); + + carry = ((top_x | top_y) & !top_z) | (top_x & top_y); + } + + for(u32bit j = y_size; j != x_size; j++) + z[j] = x[j]; + + if(!carry) return; + + for(u32bit j = y_size; j != x_size; j++) + { + z[j]++; + if(z[j]) return; + } + z[x_size]++; + } + +/************************************************* +* Two Operand Subtraction * +*************************************************/ +void bigint_sub2(word x[], u32bit x_size, const word y[], u32bit y_size) + { + word borrow = 0; + for(u32bit j = 0; j != y_size; j++) + { + word r = x[j] - y[j]; + word next = ((x[j] < r) ? 1 : 0); + r -= borrow; + borrow = next | ((r == MP_WORD_MAX) ? borrow : 0); + x[j] = r; + } + + if(!borrow) return; + + for(u32bit j = y_size; j != x_size; j++) + { + x[j]--; + if(x[j] != MP_WORD_MAX) return; + } + } + +/************************************************* +* Three Operand Subtraction * +*************************************************/ +void bigint_sub3(word z[], const word x[], u32bit x_size, + const word y[], u32bit y_size) + { + word borrow = 0; + for(u32bit j = 0; j != y_size; j++) + { + z[j] = x[j] - y[j]; + word next = ((x[j] < z[j]) ? 1 : 0); + z[j] -= borrow; + borrow = next | ((z[j] == MP_WORD_MAX) ? borrow : 0); + } + + for(u32bit j = y_size; j != x_size; j++) + z[j] = x[j]; + + if(!borrow) return; + + for(u32bit j = y_size; j != x_size; j++) + { + z[j]--; + if(z[j] != MP_WORD_MAX) return; + } + } + +} --- botan/mp_core.h +++ botan/mp_core.h @@ -0,0 +1,82 @@ +/************************************************* +* MPI Algorithms Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MP_CORE_H__ +#define BOTAN_MP_CORE_H__ + +#include + +namespace Botan { + +/************************************************* +* The size of the word type, in bits * +*************************************************/ +const u32bit MP_WORD_BITS = BOTAN_MP_WORD_BITS; + +/************************************************* +* Two Argument MP Core * +*************************************************/ +void bigint_add2(word[], u32bit, const word[], u32bit); +void bigint_sub2(word[], u32bit, const word[], u32bit); +void bigint_linmul2(word[], u32bit, word); + +/************************************************* +* Three Argument MP Core * +*************************************************/ +void bigint_add3(word[], const word[], u32bit, const word[], u32bit); +void bigint_sub3(word[] , const word[], u32bit, const word[], u32bit); +void bigint_linmul3(word[], const word[], u32bit, word); + +/************************************************* +* MP Shifting * +*************************************************/ +void bigint_shl1(word[], u32bit, u32bit, u32bit); +void bigint_shl2(word[], const word[], u32bit, u32bit, u32bit); +void bigint_shr1(word[], u32bit, u32bit, u32bit); +void bigint_shr2(word[], const word[], u32bit, u32bit, u32bit); + +/************************************************* +* Comba Multiplication * +*************************************************/ +void bigint_comba4(word[8], const word[4], const word[4]); +void bigint_comba6(word[12], const word[6], const word[6]); +void bigint_comba8(word[16], const word[8], const word[8]); + +/************************************************* +* Karatsuba Multiplication * +*************************************************/ +void bigint_karat16(word[32], const word[16], const word[16]); +void bigint_karat32(word[64], const word[32], const word[32]); +void bigint_karat64(word[128], const word[64], const word[64]); +void bigint_karat128(word[256], const word[128], const word[128]); + +void bigint_karat12(word[24], const word[12], const word[12]); +void bigint_karat24(word[48], const word[24], const word[24]); +void bigint_karat48(word[96], const word[48], const word[48]); +void bigint_karat96(word[192], const word[96], const word[96]); + +/************************************************* +* Simple O(N^2) Multiplication * +*************************************************/ +void bigint_smul(word[], const word[], u32bit, const word[], u32bit); + +/************************************************* +* MP Multiplication * +*************************************************/ +void bigint_mul3(word[], u32bit, const word[], u32bit, u32bit, + const word[], u32bit, u32bit); + +/************************************************* +* Misc MP Algorithms * +*************************************************/ +u32bit bigint_divcore(word, word, word, word, word, word); +s32bit bigint_cmp(const word[], u32bit, const word[], u32bit); +word bigint_divop(word, word, word); +word bigint_modop(word, word, word); +void bigint_wordmul(word, word, word*, word*); + +} + +#endif --- botan/mp_fkmul.cpp +++ botan/mp_fkmul.cpp @@ -0,0 +1,138 @@ +/************************************************* +* Fixed Karatsuba Multiplication Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Karatsuba Multiplication Operation * +*************************************************/ +#define KARATSUBA_CORE(N, INNER_MUL, z, x, y) \ + { \ + const u32bit 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); \ + \ + bool positive = (cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0); \ + \ + word ws[N+N+1] = { 0 }; \ + word* middle = ws + N; \ + \ + if(cmp0 && cmp1) \ + { \ + if(cmp0 > 0) \ + bigint_sub3(middle, x0, N2, x1, N2); \ + else \ + bigint_sub3(middle, x1, N2, x0, N2); \ + \ + if(cmp1 > 0) \ + bigint_sub3(z, y1, N2, y0, N2); \ + else \ + bigint_sub3(z, y0, N2, y1, N2); \ + \ + INNER_MUL(ws, middle, z); \ + } \ + \ + INNER_MUL(z0, x0, y0); \ + INNER_MUL(z1, x1, y1); \ + \ + bigint_add3(middle, z0, N, z1, N); \ + \ + if(positive) \ + bigint_add2(middle, N+1, ws, N); \ + else \ + { \ + const s32bit scmp = bigint_cmp(middle, N+1, ws, N); \ + \ + if(scmp < 0) \ + throw Internal_Error("bigint_karat" + to_string(N) + \ + ": scmp < 0"); \ + \ + if(scmp > 0) \ + bigint_sub2(middle, N+1, ws, N); \ + else \ + clear_mem(middle, N+1); \ + } \ + bigint_add2(z + N2, 2*N-N2, middle, N+1); \ + \ + clear_mem(ws, 2*N+1); \ + } + +/************************************************* +* Karatsuba 16x16 Multiplication * +*************************************************/ +void bigint_karat16(word z[32], const word x[16], const word y[16]) + { + KARATSUBA_CORE(16, bigint_comba8, z, x, y); + } + +/************************************************* +* Karatsuba 32x32 Multiplication * +*************************************************/ +void bigint_karat32(word z[64], const word x[32], const word y[32]) + { + KARATSUBA_CORE(32, bigint_karat16, z, x, y); + } + +/************************************************* +* Karatsuba 64x64 Multiplication * +*************************************************/ +void bigint_karat64(word z[128], const word x[64], const word y[64]) + { + KARATSUBA_CORE(64, bigint_karat32, z, x, y); + } + +/************************************************* +* Karatsuba 128x128 Multiplication * +*************************************************/ +void bigint_karat128(word z[256], const word x[128], const word y[128]) + { + KARATSUBA_CORE(128, bigint_karat64, z, x, y); + } + +/************************************************* +* Karatsuba 12x12 Multiplication * +*************************************************/ +void bigint_karat12(word z[24], const word x[12], const word y[12]) + { + KARATSUBA_CORE(12, bigint_comba6, z, x, y); + } + +/************************************************* +* Karatsuba 24x24 Multiplication * +*************************************************/ +void bigint_karat24(word z[48], const word x[24], const word y[24]) + { + KARATSUBA_CORE(24, bigint_karat12, z, x, y); + } + +/************************************************* +* Karatsuba 48x48 Multiplication * +*************************************************/ +void bigint_karat48(word z[96], const word x[48], const word y[48]) + { + KARATSUBA_CORE(48, bigint_karat24, z, x, y); + } + +/************************************************* +* Karatsuba 96x96 Multiplication * +*************************************************/ +void bigint_karat96(word z[192], const word x[96], const word y[96]) + { + KARATSUBA_CORE(96, bigint_karat48, z, x, y); + } + +} --- botan/mp_madd.h +++ botan/mp_madd.h @@ -0,0 +1,38 @@ +/************************************************* +* MPI Multiply-Add Core Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MP_MADD_H__ +#define BOTAN_MP_MADD_H__ + +#include + +namespace Botan { + +/************************************************* +* Multiply-Add Operation * +*************************************************/ +inline void bigint_madd(word a, word b, word c, word d, + word* out_low, word* out_high) + { +#if (BOTAN_MP_WORD_BITS == 8) + typedef Botan::u16bit dword; +#elif (BOTAN_MP_WORD_BITS == 16) + typedef Botan::u32bit dword; +#elif (BOTAN_MP_WORD_BITS == 32) + typedef Botan::u64bit dword; +#elif (BOTAN_MP_WORD_BITS == 64) + #error BOTAN_MP_WORD_BITS can only be 64 with the mp_asm64 module +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + + dword z = (dword)a * b + c + d; + *out_low = (word)((z ) & MP_WORD_MAX); + *out_high = (word)((z >> BOTAN_MP_WORD_BITS) & MP_WORD_MAX); + } + +} + +#endif --- botan/mp_misc.cpp +++ botan/mp_misc.cpp @@ -0,0 +1,114 @@ +/************************************************* +* MP Misc Functions Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Core Division Operation * +*************************************************/ +u32bit bigint_divcore(word q, word y1, word y2, + word x1, word x2, word x3) + { + word y0 = 0; + bigint_madd(q, y2, 0, 0, &y2, &y0); + bigint_madd(q, y1, y0, 0, &y1, &y0); + + if(y0 > x1) return 1; + if(y0 < x1) return 0; + if(y1 > x2) return 1; + if(y1 < x2) return 0; + if(y2 > x3) return 1; + if(y2 < x3) return 0; + return 0; + } + +/************************************************* +* Compare two MP integers * +*************************************************/ +s32bit bigint_cmp(const word x[], u32bit x_size, + const word y[], u32bit 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(u32bit j = x_size; j > 0; j--) + { + if(x[j-1] > y[j-1]) return 1; + if(x[j-1] < y[j-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; + word quotient = 0; + for(u32bit j = 0; j != MP_WORD_BITS; j++) + { + const word mask = (word)1 << (MP_WORD_BITS-1-j); + const bool high_top_bit = (high & MP_WORD_TOP_BIT) ? true : false; + + high = (high << 1) | ((n0 & mask) >> (MP_WORD_BITS-1-j)); + + if(high_top_bit || high >= d) + { + high -= d; + quotient |= mask; + } + } + return quotient; + } + +/************************************************* +* Do a 2-word/1-word Modulo * +*************************************************/ +word bigint_modop(word n1, word n0, word d) + { + word z0 = n1 / d, z1 = bigint_divop(n1, n0, d); + word carry = 0; + bigint_madd(z1, d, 0, 0, &z1, &carry); + bigint_madd(z0, d, carry, 0, &z0, &carry); + return (n0-z1); + } + +/************************************************* +* Do a word*word->2-word Multiply * +*************************************************/ +void bigint_wordmul(word a, word b, word* out_low, word* out_high) + { + const u32bit MP_HWORD_BITS = MP_WORD_BITS / 2; + const word MP_HWORD_MASK = ((word)1 << MP_HWORD_BITS) - 1; + + const word a_hi = (a >> MP_HWORD_BITS); + const word a_lo = (a & MP_HWORD_MASK); + const word b_hi = (b >> MP_HWORD_BITS); + const word b_lo = (b & MP_HWORD_MASK); + + word x0 = a_hi * b_hi; + word x1 = a_lo * b_hi; + word x2 = a_hi * b_lo; + word x3 = a_lo * b_lo; + + x2 += x3 >> (MP_HWORD_BITS); + x2 += x1; + if(x2 < x1) + x0 += (1 << MP_HWORD_BITS); + + *out_high = x0 + (x2 >> MP_HWORD_BITS); + *out_low = ((x2 & MP_HWORD_MASK) << MP_HWORD_BITS) + (x3 & MP_HWORD_MASK); + } + +} --- botan/mp_mul.cpp +++ botan/mp_mul.cpp @@ -0,0 +1,85 @@ +/************************************************* +* MP Multiplication Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +namespace { + +/************************************************* +* Length Checking * +*************************************************/ +bool use_op(u32bit x_sw, u32bit y_sw, + u32bit x_size, u32bit y_size, u32bit z_size, + u32bit limit, u32bit min = 0) + { + return (x_sw <= limit && y_sw <= limit && + x_size >= limit && y_size >= limit && z_size >= 2*limit && + (x_sw + y_sw) >= min); + } + +/************************************************* +* Attempt a Karatsuba multiply * +*************************************************/ +bool do_karat(word z[], u32bit z_size, + const word x[], u32bit x_size, u32bit x_sw, + const word y[], u32bit y_size, u32bit y_sw) + { + const u32bit KARAT_12_BOUND = 20; + const u32bit KARAT_16_BOUND = 24; + const u32bit KARAT_24_BOUND = 38; + const u32bit KARAT_32_BOUND = 46; + const u32bit KARAT_48_BOUND = 66; + const u32bit KARAT_64_BOUND = 80; + const u32bit KARAT_96_BOUND = 114; + const u32bit KARAT_128_BOUND = 136; + + if(use_op(x_sw, y_sw, x_size, y_size, z_size, 12, KARAT_12_BOUND)) + bigint_karat12(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 16, KARAT_16_BOUND)) + bigint_karat16(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 24, KARAT_24_BOUND)) + bigint_karat24(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 32, KARAT_32_BOUND)) + bigint_karat32(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 48, KARAT_48_BOUND)) + bigint_karat48(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 64, KARAT_64_BOUND)) + bigint_karat64(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 96, KARAT_96_BOUND)) + bigint_karat96(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 128, KARAT_128_BOUND)) + bigint_karat128(z, x, y); + else + return false; + + return true; + } + + +} + +/************************************************* +* MP Multiplication Algorithm Dispatcher * +*************************************************/ +void bigint_mul3(word z[], u32bit z_size, + const word x[], u32bit x_size, u32bit x_sw, + const word y[], u32bit y_size, u32bit 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(use_op(x_sw, y_sw, x_size, y_size, z_size, 4)) + bigint_comba4(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 6)) + bigint_comba6(z, x, y); + else if(use_op(x_sw, y_sw, x_size, y_size, z_size, 8)) + bigint_comba8(z, x, y); + else if(!do_karat(z, z_size, x, x_size, x_sw, y, y_size, y_sw)) + bigint_smul(z, x, x_sw, y, y_sw); + } + +} --- botan/mp_shift.cpp +++ botan/mp_shift.cpp @@ -0,0 +1,105 @@ +/************************************************* +* MP Shift Algorithms Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Single Operand Left Shift * +*************************************************/ +void bigint_shl1(word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) + { + if(word_shift) + { + for(u32bit 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(u32bit 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[], u32bit x_size, u32bit word_shift, u32bit bit_shift) + { + if(x_size < word_shift) + { + clear_mem(x, x_size); + return; + } + + for(u32bit j = 0; j != x_size - word_shift; j++) + x[j] = x[j + word_shift]; + for(u32bit j = x_size - word_shift; j != x_size; j++) + x[j] = 0; + + if(bit_shift) + { + word carry = 0; + for(u32bit j = x_size - word_shift; j > 0; j--) + { + word temp = x[j-1]; + x[j-1] = (temp >> bit_shift) | carry; + carry = (temp << (MP_WORD_BITS - bit_shift)); + } + } + } + +/************************************************* +* Two Operand Left Shift * +*************************************************/ +void bigint_shl2(word y[], const word x[], u32bit x_size, + u32bit word_shift, u32bit bit_shift) + { + for(u32bit j = 0; j != x_size; j++) + y[j + word_shift] = x[j]; + if(bit_shift) + { + word carry = 0; + for(u32bit j = word_shift; j != x_size + word_shift + 1; j++) + { + word temp = y[j]; + y[j] = (temp << bit_shift) | carry; + carry = (temp >> (MP_WORD_BITS - bit_shift)); + } + } + } + +/************************************************* +* Two Operand Right Shift * +*************************************************/ +void bigint_shr2(word y[], const word x[], u32bit x_size, + u32bit word_shift, u32bit bit_shift) + { + if(x_size < word_shift) return; + + for(u32bit j = 0; j != x_size - word_shift; j++) + y[j] = x[j + word_shift]; + if(bit_shift) + { + word carry = 0; + for(u32bit j = x_size - word_shift; j > 0; j--) + { + word temp = y[j-1]; + y[j-1] = (temp >> bit_shift) | carry; + carry = (temp << (MP_WORD_BITS - bit_shift)); + } + } + } + +} --- botan/mp_smul.cpp +++ botan/mp_smul.cpp @@ -0,0 +1,68 @@ +/************************************************* +* Simple Multiplication Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Two Operand Linear Multiply * +*************************************************/ +void bigint_linmul2(word x[], u32bit x_size, word y) + { + word carry = 0; + for(u32bit j = 0; j != x_size; j++) + bigint_madd(x[j], y, carry, 0, x + j, &carry); + x[x_size] = carry; + } + +/************************************************* +* Three Operand Linear Multiply * +*************************************************/ +void bigint_linmul3(word z[], const word x[], u32bit x_size, word y) + { + word carry = 0; + for(u32bit j = 0; j != x_size; j++) + bigint_madd(x[j], y, carry, 0, z + j, &carry); + z[x_size] = carry; + } + +/************************************************* +* Simple O(N^2) Multiplication * +*************************************************/ +void bigint_smul(word z[], const word x[], u32bit x_size, + const word y[], u32bit y_size) + { + const u32bit blocks = y_size - (y_size % 8); + + clear_mem(z, x_size + y_size); + + for(u32bit j = 0; j != x_size; j++) + { + const word x_j = x[j]; + + word carry = 0; + + for(u32bit k = 0; k != blocks; k += 8) + { + bigint_madd(x_j, y[k+0], z[j+k+0], carry, z + (j+k+0), &carry); + bigint_madd(x_j, y[k+1], z[j+k+1], carry, z + (j+k+1), &carry); + bigint_madd(x_j, y[k+2], z[j+k+2], carry, z + (j+k+2), &carry); + bigint_madd(x_j, y[k+3], z[j+k+3], carry, z + (j+k+3), &carry); + bigint_madd(x_j, y[k+4], z[j+k+4], carry, z + (j+k+4), &carry); + bigint_madd(x_j, y[k+5], z[j+k+5], carry, z + (j+k+5), &carry); + bigint_madd(x_j, y[k+6], z[j+k+6], carry, z + (j+k+6), &carry); + bigint_madd(x_j, y[k+7], z[j+k+7], carry, z + (j+k+7), &carry); + } + + for(u32bit k = blocks; k != y_size; k++) + bigint_madd(x_j, y[k], z[j+k], carry, z + (j+k), &carry); + z[j+y_size] = carry; + } + } + +} --- botan/mp_types.h +++ botan/mp_types.h @@ -0,0 +1,32 @@ +/************************************************* +* Low Level MPI Types Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MPI_TYPES_H__ +#define BOTAN_MPI_TYPES_H__ + +#include +#include + +namespace Botan { + +#if (BOTAN_MP_WORD_BITS == 8) + typedef byte word; +#elif (BOTAN_MP_WORD_BITS == 16) + typedef u16bit word; +#elif (BOTAN_MP_WORD_BITS == 32) + typedef u32bit word; +#elif (BOTAN_MP_WORD_BITS == 64) + typedef u64bit word; +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +const word MP_WORD_MASK = ~((word)0); +const word MP_WORD_TOP_BIT = (word)1 << (8*sizeof(word) - 1); +const word MP_WORD_MAX = MP_WORD_MASK; + +} + +#endif --- botan/mutex.cpp +++ botan/mutex.cpp @@ -0,0 +1,107 @@ +/************************************************* +* Mutex Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Global Mutex Variables * +*************************************************/ +Mutex* mutex_factory = 0; +Mutex* mutex_init_lock = 0; + +/************************************************* +* Default Mutex * +*************************************************/ +class Default_Mutex : public Mutex + { + public: + void lock(); + void unlock(); + Mutex* clone() const { return new Default_Mutex; } + Default_Mutex() { locked = false; } + private: + bool locked; + }; + +/************************************************* +* Lock the mutex * +*************************************************/ +void Default_Mutex::lock() + { + if(locked) + { + abort(); + throw Internal_Error("Default_Mutex::lock: Mutex is already locked"); + } + locked = true; + } + +/************************************************* +* Unlock the mutex * +*************************************************/ +void Default_Mutex::unlock() + { + if(!locked) + { + abort(); + throw Internal_Error("Default_Mutex::unlock: Mutex is already unlocked"); + } + locked = false; + } + +} + +/************************************************* +* Get a mew mutex * +*************************************************/ +Mutex* get_mutex() + { + if(mutex_factory == 0) + return new Default_Mutex; + return mutex_factory->clone(); + } + +/************************************************* +* Initialize a mutex atomically * +*************************************************/ +void initialize_mutex(Mutex*& mutex) + { + if(mutex) return; + + if(mutex_init_lock) + { + Mutex_Holder lock(mutex_init_lock); + if(mutex == 0) + mutex = get_mutex(); + } + else + mutex = get_mutex(); + } + +namespace Init { + +/************************************************* +* Set the Mutex type * +*************************************************/ +void set_mutex_type(Mutex* mutex) + { + delete mutex_factory; + delete mutex_init_lock; + + mutex_factory = mutex; + + if(mutex) mutex_init_lock = get_mutex(); + else mutex_init_lock = 0; + } + +} + +} --- botan/mutex.h +++ botan/mutex.h @@ -0,0 +1,43 @@ +/************************************************* +* Mutex Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MUTEX_H__ +#define BOTAN_MUTEX_H__ + +namespace Botan { + +/************************************************* +* Mutex Base Class * +*************************************************/ +class Mutex + { + public: + virtual void lock() = 0; + virtual void unlock() = 0; + virtual Mutex* clone() const = 0; + virtual ~Mutex() {} + }; + +/************************************************* +* Mutex Holding Class * +*************************************************/ +class Mutex_Holder + { + public: + Mutex_Holder(Mutex* m) : mux(m) { mux->lock(); } + ~Mutex_Holder() { mux->unlock(); } + private: + Mutex* mux; + }; + +/************************************************* +* Get/set a mutex * +*************************************************/ +Mutex* get_mutex(); +void initialize_mutex(Mutex*&); + +} + +#endif --- botan/numthry.cpp +++ botan/numthry.cpp @@ -0,0 +1,391 @@ +/************************************************* +* Number Theory Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Miller-Rabin Iterations * +*************************************************/ +u32bit miller_rabin_test_iterations(u32bit bits, bool verify) + { + struct mapping { u32bit bits; u32bit verify_iter; u32bit check_iter; }; + + static 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(u32bit j = 0; tests[j].bits; j++) + { + if(bits <= tests[j].bits) + if(verify) + return tests[j].verify_iter; + else + return tests[j].check_iter; + } + return 2; + } + +} + +/************************************************* +* Return the number of 0 bits at the end of n * +*************************************************/ +u32bit low_zero_bits(const BigInt& n) + { + if(n.is_zero()) return 0; + + u32bit bits = 0, max_bits = n.bits(); + while((n.get_bit(bits) == 0) && bits < max_bits) bits++; + return bits; + } + +/************************************************* +* If this number is of the form 2^n, return n * +*************************************************/ +u32bit power_of_2(const BigInt& n) + { + if(n <= 1 || n % 2 == 1) return 0; + if(n == 2) return 1; + + u32bit bit_set = 0; + + const u32bit n_bits = n.bits(); + for(u32bit j = 1; j != n_bits; j++) + if(n.get_bit(j)) + { + if(bit_set) return 0; + bit_set = j; + } + + return bit_set; + } + +/************************************************* +* 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); + u32bit 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)); + } + +/************************************************* +* Square a BigInt * +*************************************************/ +BigInt square(const BigInt& a) + { + return (a * a); + } + +/************************************************* +* 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; + + BigInt x = mod, y = n, u = mod, v = n; + BigInt A = 1, B = 0, C = 0, D = 1; + + while(u.is_nonzero()) + { + u32bit zero_bits = low_zero_bits(u); + u >>= zero_bits; + for(u32bit j = 0; j != zero_bits; j++) + { + if(A.is_odd() || B.is_odd()) + { A += y; B -= x; } + A >>= 1; B >>= 1; + } + + zero_bits = low_zero_bits(v); + v >>= zero_bits; + for(u32bit j = 0; j != zero_bits; j++) + { + if(C.is_odd() || D.is_odd()) + { C += y; D -= x; } + 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; + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +/************************************************* +* 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; + while(x % 4 == 0) + x >>= 2; + if(x.is_even()) + { + x >>= 1; + if(y % 8 == 3 || y % 8 == 5) + J = -J; + } + if(x % 4 == 3 && y % 4 == 3) + J = -J; + std::swap(x, y); + } + return J; + } + +/************************************************* +* Exponentiation * +*************************************************/ +BigInt power(const BigInt& base, u32bit exp) + { + BigInt x = 1, a = base; + while(exp) + { + if(exp % 2) + x *= a; + exp >>= 1; + if(exp) + a = square(a); + } + return x; + } + +/************************************************* +* Do simple tests of primality * +*************************************************/ +s32bit simple_primality_tests(const BigInt& n) + { + const s32bit NOT_PRIME = -1, UNKNOWN = 0, PRIME = 1; + + if(n == 2) + return PRIME; + if(n <= 1 || n.is_even()) + return NOT_PRIME; + + if(n <= PRIMES[PRIME_TABLE_SIZE-1]) + { + const u32bit num = n.word_at(0); + for(u32bit j = 0; PRIMES[j]; j++) + { + if(num == PRIMES[j]) return PRIME; + if(num < PRIMES[j]) return NOT_PRIME; + } + return NOT_PRIME; + } + + u32bit check_first = std::min(n.bits() / 32, PRIME_PRODUCTS_TABLE_SIZE); + for(u32bit j = 0; j != check_first; j++) + if(gcd(n, PRIME_PRODUCTS[j]) != 1) + return NOT_PRIME; + + return UNKNOWN; + } + +/************************************************* +* Fast check of primality * +*************************************************/ +bool check_prime(const BigInt& n) + { + return run_primality_tests(n, 0); + } + +/************************************************* +* Test for primality * +*************************************************/ +bool is_prime(const BigInt& n) + { + return run_primality_tests(n, 1); + } + +/************************************************* +* Verify primality * +*************************************************/ +bool verify_prime(const BigInt& n) + { + return run_primality_tests(n, 2); + } + +/************************************************* +* Verify primality * +*************************************************/ +bool run_primality_tests(const BigInt& n, u32bit level) + { + s32bit simple_tests = simple_primality_tests(n); + if(simple_tests) return (simple_tests == 1) ? true : false; + return passes_mr_tests(n, level); + } + +/************************************************* +* Test for primaility using Miller-Rabin * +*************************************************/ +bool passes_mr_tests(const BigInt& n, u32bit level) + { + const u32bit PREF_NONCE_BITS = 40; + + if(level > 2) + level = 2; + + MillerRabin_Test mr(n); + + if(!mr.passes_test(2)) + return false; + + if(level == 0) + return true; + + const u32bit NONCE_BITS = std::min(n.bits() - 1, PREF_NONCE_BITS); + + const bool verify = (level == 2); + + u32bit tests = miller_rabin_test_iterations(n.bits(), verify); + + BigInt nonce; + for(u32bit j = 0; j != tests; j++) + { + nonce = (verify) ? (random_integer(NONCE_BITS, Nonce)) : (PRIMES[j]); + if(!mr.passes_test(nonce)) + return false; + } + return true; + } + +/************************************************* +* Miller-Rabin Test * +*************************************************/ +bool MillerRabin_Test::passes_test(const BigInt& a) + { + if(a < 2 || a >= n_minus_1) + throw Invalid_Argument("Bad size for nonce in Miller-Rabin test"); + + UI::pulse(UI::PRIME_TESTING); + BigInt y = power_mod(a, r, reducer); + + if(y == 1 || y == n_minus_1) + return true; + + for(u32bit j = 1; j != s; j++) + { + UI::pulse(UI::PRIME_TESTING); + y = reducer->square(y); + if(y == 1) + return false; + if(y == n_minus_1) + 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; + + reducer = get_reducer(n); + } + +} --- botan/numthry.h +++ botan/numthry.h @@ -0,0 +1,103 @@ +/************************************************* +* Number Theory Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_NUMBTHRY_H__ +#define BOTAN_NUMBTHRY_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Fused Arithmetic Operations * +*************************************************/ +BigInt mul_add(const BigInt&, const BigInt&, const BigInt&); +BigInt sub_mul(const BigInt&, const BigInt&, const BigInt&); +BigInt mul_mod(const BigInt&, const BigInt&, const BigInt&); + +/************************************************* +* Number Theory Functions * +*************************************************/ +inline BigInt abs(const BigInt& n) { return n.abs(); } + +void divide(const BigInt&, const BigInt&, BigInt&, BigInt&); +void positive_divide(const BigInt&, const BigInt&, BigInt&, BigInt&); +void modifying_divide(BigInt&, BigInt&, BigInt&); + +BigInt gcd(const BigInt&, const BigInt&); +BigInt lcm(const BigInt&, const BigInt&); + +BigInt square(const BigInt&); +BigInt inverse_mod(const BigInt&, const BigInt&); +s32bit jacobi(const BigInt&, const BigInt&); +BigInt power(const BigInt&, u32bit); + +/************************************************* +* Modular Exponentiation * +*************************************************/ +BigInt power_mod(const BigInt&, const BigInt&, ModularReducer*); +BigInt power_mod(const BigInt&, const BigInt&, const BigInt&); + +/************************************************* +* Utility Functions * +*************************************************/ +u32bit low_zero_bits(const BigInt&); +u32bit power_of_2(const BigInt&); + +/************************************************* +* Primality Testing * +*************************************************/ +bool check_prime(const BigInt&); +bool is_prime(const BigInt&); +bool verify_prime(const BigInt&); + +s32bit simple_primality_tests(const BigInt&); +bool passes_mr_tests(const BigInt&, u32bit = 1); +bool run_primality_tests(const BigInt&, u32bit = 1); + +/************************************************* +* Random Number Generation * +*************************************************/ +BigInt random_integer(u32bit, RNG_Quality = SessionKey); +BigInt random_integer(const BigInt&, const BigInt&, RNG_Quality = SessionKey); +BigInt random_prime(u32bit, RNG_Quality = SessionKey, const BigInt& = 1, + u32bit = 1, u32bit = 2); +BigInt random_safe_prime(u32bit, RNG_Quality = SessionKey); + +SecureVector generate_dsa_primes(BigInt&, BigInt&, u32bit); +bool generate_dsa_primes(BigInt&, BigInt&, const byte[], u32bit, u32bit, + u32bit = 0); + +/************************************************* +* Prime Numbers * +*************************************************/ +const u32bit PRIME_TABLE_SIZE = 6541; +const u32bit PRIME_PRODUCTS_TABLE_SIZE = 256; + +extern const u16bit PRIMES[]; +extern const u64bit PRIME_PRODUCTS[]; + +/************************************************* +* Miller-Rabin Primality Tester * +*************************************************/ +class MillerRabin_Test + { + public: + bool passes_test(const BigInt&); + + MillerRabin_Test(const BigInt&); + ~MillerRabin_Test() { delete reducer; } + private: + MillerRabin_Test(const MillerRabin_Test&) {} + MillerRabin_Test& operator=(const MillerRabin_Test&) { return (*this); } + BigInt n, r, n_minus_1; + u32bit s; + ModularReducer* reducer; + }; + +} + +#endif --- botan/ofb.cpp +++ botan/ofb.cpp @@ -0,0 +1,63 @@ +/************************************************* +* OFB Mode Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* OFB Constructor * +*************************************************/ +OFB::OFB(const std::string& cipher_name) : + BlockCipherMode(cipher_name, "OFB", block_size_of(cipher_name), 2) + { + } + +/************************************************* +* OFB Constructor * +*************************************************/ +OFB::OFB(const std::string& cipher_name, const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(cipher_name, "OFB", block_size_of(cipher_name), 2) + { + set_key(key); + set_iv(iv); + } + +/************************************************* +* OFB Encryption/Decryption * +*************************************************/ +void OFB::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer, input, state + position, copied); + send(buffer, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + { + cipher->encrypt(state); + position = 0; + } + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, state, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + cipher->encrypt(state); + } + + xor_buf(buffer, input, state + position, length); + send(buffer, length); + position += length; + } + +} --- botan/ofb.h +++ botan/ofb.h @@ -0,0 +1,28 @@ +/************************************************* +* OFB Mode Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_OFB_H__ +#define BOTAN_OFB_H__ + +#include + +namespace Botan { + +/************************************************* +* OFB Mode * +*************************************************/ +class OFB : public BlockCipherMode + { + public: + OFB(const std::string&); + OFB(const std::string&, + const SymmetricKey&, const InitializationVector&); + private: + void write(const byte[], u32bit); + }; + +} + +#endif --- botan/oids.cpp +++ botan/oids.cpp @@ -0,0 +1,78 @@ +/************************************************* +* OID Registry Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace OIDS { + +namespace { + +std::map oid_to_str; +std::map str_to_oid; +Mutex* oid_mutex = 0; + +} + +/************************************************* +* Register an OID to string mapping * +*************************************************/ +void add_oid(const OID& oid, const std::string& name) + { + initialize_mutex(oid_mutex); + Mutex_Holder lock(oid_mutex); + + if(oid_to_str.find(oid) == oid_to_str.end()) + oid_to_str[oid] = name; + if(str_to_oid.find(name) == str_to_oid.end()) + str_to_oid[name] = oid; + } + +/************************************************* +* Do an OID to string lookup * +*************************************************/ +std::string lookup(const OID& oid) + { + initialize_mutex(oid_mutex); + Mutex_Holder lock(oid_mutex); + + std::map::const_iterator info = oid_to_str.find(oid); + if(info == oid_to_str.end()) + return oid.as_string(); + return info->second; + } + +/************************************************* +* Do a string to OID lookup * +*************************************************/ +OID lookup(const std::string& name) + { + initialize_mutex(oid_mutex); + Mutex_Holder lock(oid_mutex); + + std::map::const_iterator info = str_to_oid.find(name); + if(info == str_to_oid.end()) + throw Lookup_Error("No known OID for " + name); + return info->second; + } + +/************************************************* +* Check to see if an OID exists in the table * +*************************************************/ +bool have_oid(const std::string& name) + { + initialize_mutex(oid_mutex); + Mutex_Holder lock(oid_mutex); + + return (str_to_oid.find(name) != str_to_oid.end()); + } + +} + +} --- botan/oids.h +++ botan/oids.h @@ -0,0 +1,39 @@ +/************************************************* +* OID Registry Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_OIDS_H__ +#define BOTAN_OIDS_H__ + +#include + +namespace Botan { + +namespace OIDS { + +/************************************************* +* Register an OID to string mapping * +*************************************************/ +void add_oid(const OID&, const std::string&); + +/************************************************* +* Do an OID to string lookup * +*************************************************/ +std::string lookup(const OID&); + +/************************************************* +* Do a string to OID lookup * +*************************************************/ +OID lookup(const std::string&); + +/************************************************* +* See if an OID exists in the internal table * +*************************************************/ +bool have_oid(const std::string&); + +} + +} + +#endif --- botan/omac.h +++ botan/omac.h @@ -0,0 +1,37 @@ +/************************************************* +* OMAC Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_OMAC_H__ +#define BOTAN_OMAC_H__ + +#include + +namespace Botan { + +/************************************************* +* OMAC * +*************************************************/ +class OMAC : public MessageAuthenticationCode + { + public: + void clear() throw(); + std::string name() const; + MessageAuthenticationCode* clone() const; + OMAC(const std::string&); + ~OMAC() { delete e; } + private: + void add_data(const byte[], u32bit); + void final_result(byte[]); + void key(const byte[], u32bit); + + BlockCipher* e; + SecureVector buffer, state, B, P; + u32bit position; + byte polynomial; + }; + +} + +#endif --- botan/par_hash.h +++ botan/par_hash.h @@ -0,0 +1,33 @@ +/************************************************* +* Parallel Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PAR_HASH_H__ +#define BOTAN_PAR_HASH_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Parallel * +*************************************************/ +class Parallel : public HashFunction + { + public: + void clear() throw(); + std::string name() const; + HashFunction* clone() const; + Parallel(const std::vector&); + ~Parallel(); + private: + void add_data(const byte[], u32bit); + void final_result(byte[]); + std::vector hashes; + }; + +} + +#endif --- botan/parse.cpp +++ botan/parse.cpp @@ -0,0 +1,221 @@ +/************************************************* +* Parsing Functions Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* 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; + u32bit level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for(std::string::const_iterator j = name.begin(); j != name.end(); j++) + { + char c = *j; + + if(c == '(') + level++; + if(c == ')') + { + if(level == 1 && j == 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 && j != 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 = ""; + } + 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(std::string::const_iterator j = str.begin(); j != str.end(); j++) + { + if(*j == delim) + { + elems.push_back(substr); + substr = ""; + } + else + substr += *j; + } + + if(substr == "") + throw Format_Error("Unable to split string: " + str); + elems.push_back(substr); + + return elems; + } + +/************************************************* +* Parse an ASN.1 OID string * +*************************************************/ +std::vector parse_asn1_oid(const std::string& oid) + { + std::string substring; + std::vector oid_elems; + + for(std::string::const_iterator j = oid.begin(); j != oid.end(); j++) + { + char c = *j; + + if(c == '.') + { + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + substring = ""; + } + 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) + { + std::string::const_iterator p1 = name1.begin(); + std::string::const_iterator p2 = name2.begin(); + + while((p1 != name1.end()) && is_space(*p1)) p1++; + while((p2 != name2.end()) && is_space(*p2)) p2++; + + while(p1 != name1.end() && p2 != name2.end()) + { + if(is_space(*p1)) + { + if(!is_space(*p2)) + return false; + + while((p1 != name1.end()) && is_space(*p1)) p1++; + while((p2 != name2.end()) && is_space(*p2)) p2++; + + if(p1 == name1.end() && p2 == name2.end()) + return true; + } + + if(to_lower(*p1) != to_lower(*p2)) + return false; + p1++; + p2++; + } + + while((p1 != name1.end()) && is_space(*p1)) p1++; + while((p2 != name2.end()) && is_space(*p2)) p2++; + + if((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; + } + +/************************************************* +* Convert from UTF-8 to ISO 8859-1 * +*************************************************/ +std::string utf2iso(const std::string& utf8) + { + std::string iso8859; + + u32bit position = 0; + while(position != utf8.size()) + { + const byte c1 = (byte)utf8[position++]; + + if(c1 <= 0x7F) + iso8859 += (char)c1; + else if(c1 >= 0xC0 && c1 <= 0xC7) + { + if(position == utf8.size()) + throw Decoding_Error("UTF-8: sequence truncated"); + + const byte c2 = (byte)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 += (char)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 iso2utf(const std::string& iso8859) + { + std::string utf8; + for(u32bit j = 0; j != iso8859.size(); j++) + { + const byte c = (byte)iso8859[j]; + + if(c <= 0x7F) + utf8 += (char)c; + else + { + utf8 += (char)(0xC0 | (c >> 6)); + utf8 += (char)(0x80 | (c & 0x3F)); + } + } + return utf8; + } + +} --- botan/pbe.h +++ botan/pbe.h @@ -0,0 +1,36 @@ +/************************************************* +* PBE Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PBE_H__ +#define BOTAN_PBE_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Password Based Encryption * +*************************************************/ +class PBE : public Filter + { + public: + virtual void set_key(const std::string&) = 0; + virtual void new_params() = 0; + virtual MemoryVector encode_params() const = 0; + virtual void decode_params(DataSource&) = 0; + virtual OID get_oid() const = 0; + }; + +/************************************************* +* Get a PBE object * +*************************************************/ +PBE* get_pbe(const std::string&); +PBE* get_pbe(const OID&, DataSource&); + +} + +#endif --- botan/pbe_pkcs.h +++ botan/pbe_pkcs.h @@ -0,0 +1,65 @@ +/************************************************* +* PKCS PBE Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PBE_PKCS_H__ +#define BOTAN_PBE_PKCS_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* PKCS#5 v1.5 PBE * +*************************************************/ +class PBE_PKCS5v15 : public PBE + { + public: + void write(const byte[], u32bit); + void start_msg(); + void end_msg(); + PBE_PKCS5v15(const std::string&, const std::string&, Cipher_Dir); + private: + void set_key(const std::string&); + void new_params(); + MemoryVector encode_params() const; + void decode_params(DataSource&); + OID get_oid() const; + void flush_pipe(bool); + const Cipher_Dir direction; + const std::string digest, cipher; + SecureVector salt, key, iv; + u32bit iterations; + Pipe pipe; + }; + +/************************************************* +* PKCS#5 v2.0 PBE * +*************************************************/ +class PBE_PKCS5v20 : public PBE + { + public: + void write(const byte[], u32bit); + void start_msg(); + void end_msg(); + PBE_PKCS5v20(DataSource&); + PBE_PKCS5v20(const std::string&, const std::string&); + private: + void set_key(const std::string&); + void new_params(); + MemoryVector encode_params() const; + void decode_params(DataSource&); + OID get_oid() const; + void flush_pipe(bool); + const Cipher_Dir direction; + std::string digest, cipher, cipher_algo; + SecureVector salt, key, iv; + u32bit iterations, key_length; + Pipe pipe; + }; + +} + +#endif --- botan/pbes1.cpp +++ botan/pbes1.cpp @@ -0,0 +1,163 @@ +/************************************************* +* PKCS #5 PBES1 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Encrypt some bytes using PBES1 * +*************************************************/ +void PBE_PKCS5v15::write(const byte input[], u32bit length) + { + while(length) + { + u32bit put = std::min(DEFAULT_BUFFERSIZE, length); + pipe.write(input, length); + flush_pipe(true); + length -= put; + } + } + +/************************************************* +* Start encrypting with PBES1 * +*************************************************/ +void PBE_PKCS5v15::start_msg() + { + pipe.append(get_cipher(cipher, key, iv, direction)); + pipe.start_msg(); + if(pipe.message_count() > 1) + pipe.set_default_msg(pipe.default_msg() + 1); + } + +/************************************************* +* Finish encrypting with PBES1 * +*************************************************/ +void PBE_PKCS5v15::end_msg() + { + pipe.end_msg(); + flush_pipe(false); + pipe.reset(); + } + +/************************************************* +* Flush the pipe * +*************************************************/ +void PBE_PKCS5v15::flush_pipe(bool safe_to_skip) + { + if(safe_to_skip && pipe.remaining() < 64) + return; + + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + u32bit got = pipe.read(buffer, buffer.size()); + send(buffer, got); + } + } + +/************************************************* +* Set the passphrase to use * +*************************************************/ +void PBE_PKCS5v15::set_key(const std::string& passphrase) + { + std::auto_ptr pbkdf(get_s2k("PBKDF1(" + digest + ")")); + pbkdf->set_iterations(iterations); + pbkdf->change_salt(salt, salt.size()); + SymmetricKey key_and_iv = pbkdf->derive_key(16, passphrase); + + key.set(key_and_iv.begin(), 8); + iv.set(key_and_iv.begin() + 8, 8); + } + +/************************************************* +* Create a new set of PBES1 parameters * +*************************************************/ +void PBE_PKCS5v15::new_params() + { + iterations = 2048; + salt.create(8); + Global_RNG::randomize(salt, salt.size(), Nonce); + } + +/************************************************* +* Encode PKCS#5 PBES1 parameters * +*************************************************/ +MemoryVector PBE_PKCS5v15::encode_params() const + { + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, salt, OCTET_STRING); + DER::encode(encoder, iterations); + encoder.end_sequence(); + return encoder.get_contents(); + } + +/************************************************* +* Decode PKCS#5 PBES1 parameters * +*************************************************/ +void PBE_PKCS5v15::decode_params(DataSource& source) + { + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, salt, OCTET_STRING); + BER::decode(sequence, iterations); + sequence.verify_end(); + + if(salt.size() != 8) + throw Decoding_Error("PBES1: Encoded salt is not 8 octets"); + } + +/************************************************* +* Return an OID for this PBES1 type * +*************************************************/ +OID PBE_PKCS5v15::get_oid() const + { + const OID base_pbes1_oid("1.2.840.113549.1.5"); + if(cipher == "DES/CBC" && digest == "MD2") + return (base_pbes1_oid + 1); + else if(cipher == "DES/CBC" && digest == "MD5") + return (base_pbes1_oid + 3); + else if(cipher == "DES/CBC" && digest == "SHA-160") + return (base_pbes1_oid + 10); + else if(cipher == "RC2/CBC" && digest == "MD2") + return (base_pbes1_oid + 4); + else if(cipher == "RC2/CBC" && digest == "MD5") + return (base_pbes1_oid + 6); + else if(cipher == "RC2/CBC" && digest == "SHA-160") + return (base_pbes1_oid + 11); + else + throw Internal_Error("PBE-PKCS5 v1.5: get_oid() has run out of options"); + } + +/************************************************* +* PKCS#5 v1.5 PBE Constructor * +*************************************************/ +PBE_PKCS5v15::PBE_PKCS5v15(const std::string& d_algo, + const std::string& c_algo, Cipher_Dir dir) : + direction(dir), digest(deref_alias(d_algo)), cipher(c_algo) + { + std::vector cipher_spec = split_on(c_algo, '/'); + if(cipher_spec.size() != 2) + throw Invalid_Argument("PBE-PKCS5 v1.5: Invalid cipher spec " + c_algo); + const std::string cipher_algo = deref_alias(cipher_spec[0]); + const std::string cipher_mode = cipher_spec[1]; + + if(!have_block_cipher(cipher_algo)) + throw Algorithm_Not_Found(cipher_algo); + if(!have_hash(digest)) + throw Algorithm_Not_Found(digest); + + if((cipher_algo != "DES" && cipher_algo != "RC2") || (cipher_mode != "CBC")) + throw Invalid_Argument("PBE-PKCS5 v1.5: Invalid cipher " + cipher); + if(digest != "MD2" && digest != "MD5" && digest != "SHA-160") + throw Invalid_Argument("PBE-PKCS5 v1.5: Invalid digest " + digest); + } + +} --- botan/pbes2.cpp +++ botan/pbes2.cpp @@ -0,0 +1,205 @@ +/************************************************* +* PKCS #5 PBES2 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Encrypt some bytes using PBES2 * +*************************************************/ +void PBE_PKCS5v20::write(const byte input[], u32bit length) + { + while(length) + { + u32bit put = std::min(DEFAULT_BUFFERSIZE, length); + pipe.write(input, length); + flush_pipe(true); + length -= put; + } + } + +/************************************************* +* Start encrypting with PBES2 * +*************************************************/ +void PBE_PKCS5v20::start_msg() + { + pipe.append(get_cipher(cipher, 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; + + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + u32bit got = pipe.read(buffer, buffer.size()); + send(buffer, got); + } + } + +/************************************************* +* Set the passphrase to use * +*************************************************/ +void PBE_PKCS5v20::set_key(const std::string& passphrase) + { + std::auto_ptr pbkdf(get_s2k("PBKDF2(" + digest + ")")); + pbkdf->set_iterations(iterations); + pbkdf->change_salt(salt, salt.size()); + key = pbkdf->derive_key(key_length, passphrase).bits_of(); + } + +/************************************************* +* Create a new set of PBES2 parameters * +*************************************************/ +void PBE_PKCS5v20::new_params() + { + iterations = 2048; + key_length = max_keylength_of(cipher_algo); + salt.create(8); + iv.create(block_size_of(cipher_algo)); + Global_RNG::randomize(salt, salt.size(), Nonce); + Global_RNG::randomize(iv, iv.size(), Nonce); + } + +/************************************************* +* Encode PKCS#5 PBES2 parameters * +*************************************************/ +MemoryVector PBE_PKCS5v20::encode_params() const + { + AlgorithmIdentifier kdf_algo, enc_algo; + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, salt, OCTET_STRING); + DER::encode(encoder, iterations); + DER::encode(encoder, key_length); + encoder.end_sequence(); + kdf_algo.parameters = encoder.get_contents(); + kdf_algo.oid = OIDS::lookup("PKCS5.PBKDF2"); + + enc_algo.oid = OIDS::lookup(cipher); + DER::encode(encoder, iv, OCTET_STRING); + enc_algo.parameters = encoder.get_contents(); + + encoder.start_sequence(); + DER::encode(encoder, kdf_algo); + DER::encode(encoder, enc_algo); + encoder.end_sequence(); + return encoder.get_contents(); + } + +/************************************************* +* Decode PKCS#5 PBES2 parameters * +*************************************************/ +void PBE_PKCS5v20::decode_params(DataSource& source) + { + AlgorithmIdentifier kdf_algo, enc_algo; + + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, kdf_algo); + BER::decode(sequence, enc_algo); + sequence.verify_end(); + + if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2")) + { + digest = "SHA-160"; + BER_Decoder pbkdf2_params(kdf_algo.parameters); + BER_Decoder algo_params = BER::get_subsequence(pbkdf2_params); + BER::decode(algo_params, salt, OCTET_STRING); + BER::decode(algo_params, iterations); + if(algo_params.more_items()) + BER::decode(algo_params, key_length); + else + key_length = 0; + algo_params.verify_end(); + } + else + throw Decoding_Error("PBES2: Unknown KDF algorithm " + + kdf_algo.oid.as_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); + cipher_algo = deref_alias(cipher_spec[0]); + if(cipher != "DES/CBC" && cipher != "TripleDES/CBC") + throw Decoding_Error("PBES2: Don't know param format for " + cipher); + BER_Decoder algo_params(enc_algo.parameters); + BER::decode(algo_params, iv, OCTET_STRING); + + if(key_length == 0) + key_length = max_keylength_of(cipher_algo); + + if(salt.size() < 8) + throw Decoding_Error("PBES2: Encoded salt is too small"); + } + +/************************************************* +* Return an OID for PBES2 * +*************************************************/ +OID PBE_PKCS5v20::get_oid() const + { + return OIDS::lookup("PBE-PKCS5v20"); + } + +/************************************************* +* PKCS#5 v2.0 PBE Constructor * +*************************************************/ +PBE_PKCS5v20::PBE_PKCS5v20(const std::string& d_algo, + const std::string& c_algo) : + direction(ENCRYPTION), digest(deref_alias(d_algo)), cipher(c_algo) + { + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + cipher_algo = deref_alias(cipher_spec[0]); + const std::string cipher_mode = cipher_spec[1]; + + if(!have_block_cipher(cipher_algo)) + throw Algorithm_Not_Found(cipher_algo); + if(!have_hash(digest)) + throw Algorithm_Not_Found(digest); + + if((cipher_algo != "DES" && cipher_algo != "TripleDES") || + (cipher_mode != "CBC")) + throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher); + if(digest != "SHA-160") + throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest); + } + +/************************************************* +* PKCS#5 v2.0 PBE Constructor * +*************************************************/ +PBE_PKCS5v20::PBE_PKCS5v20(DataSource& params) : direction(DECRYPTION) + { + decode_params(params); + } + +} --- botan/pem.cpp +++ botan/pem.cpp @@ -0,0 +1,144 @@ +/************************************************* +* PEM Encoding/Decoding Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace PEM_Code { + +/************************************************* +* PEM encode BER/DER-encoded objects * +*************************************************/ +std::string encode(const byte der[], u32bit length, const std::string& label) + { + const u32bit PEM_WIDTH = Config::get_u32bit("pem/width"); + + if(PEM_WIDTH < 50 || PEM_WIDTH > 76) + throw Encoding_Error("PEM: Invalid line width " + to_string(PEM_WIDTH)); + + const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; + const std::string PEM_TRAILER = "-----END " + label + "-----\n"; + + Pipe pipe(new Base64_Encoder(true, PEM_WIDTH)); + pipe.process_msg(der, length); + return (PEM_HEADER + pipe.read_all_as_string() + PEM_TRAILER); + } + +/************************************************* +* PEM encode BER/DER-encoded objects * +*************************************************/ +std::string encode(const MemoryRegion& data, const std::string& label) + { + return encode(data, data.size(), label); + } + +/************************************************* +* Decode PEM down to raw BER/DER * +*************************************************/ +SecureVector decode_check_label(DataSource& source, + const std::string& label_want) + { + std::string label_got; + SecureVector 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 * +*************************************************/ +SecureVector decode(DataSource& source, std::string& label) + { + const u32bit RANDOM_CHAR_LIMIT = Config::get_u32bit("pem/forgive"); + + const std::string PEM_HEADER1 = "-----BEGIN "; + const std::string PEM_HEADER2 = "-----"; + u32bit 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 += (char)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(); + } + +/************************************************* +* Search for a PEM signature * +*************************************************/ +bool matches(DataSource& source, const std::string& extra) + { + const u32bit PEM_SEARCH_RANGE = Config::get_u32bit("pem/search"); + const std::string PEM_HEADER = "-----BEGIN " + extra; + + SecureVector search_buf(PEM_SEARCH_RANGE); + u32bit got = source.peek(search_buf, search_buf.size(), 0); + + if(got < PEM_HEADER.length()) + return false; + + u32bit index = 0; + + for(u32bit 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; + } + +} + +} --- botan/pem.h +++ botan/pem.h @@ -0,0 +1,29 @@ +/************************************************* +* PEM Encoding/Decoding Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PEM_H__ +#define BOTAN_PEM_H__ + +#include + +namespace Botan { + +namespace PEM_Code { + +/************************************************* +* PEM Encoding/Decoding * +*************************************************/ +std::string encode(const byte[], u32bit, const std::string&); +std::string encode(const MemoryRegion&, const std::string&); + +SecureVector decode(DataSource&, std::string&); +SecureVector decode_check_label(DataSource&, const std::string&); +bool matches(DataSource&, const std::string& = ""); + +} + +} + +#endif --- botan/pipe.cpp +++ botan/pipe.cpp @@ -0,0 +1,270 @@ +/************************************************* +* Pipe Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* A Filter that does nothing * +*************************************************/ +class Null_Filter : public Filter + { + public: + void write(const byte input[], u32bit length) + { send(input, length); } + }; + +} + +/************************************************* +* 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(Filter* filter_array[], u32bit count) + { + init(); + for(u32bit j = 0; j != count; j++) + append(filter_array[j]); + } + +/************************************************* +* Pipe Destructor * +*************************************************/ +Pipe::~Pipe() + { + destruct(pipe); + for(u32bit j = 0; j != messages.size(); j++) + delete messages[j]; + } + +/************************************************* +* Initialize the Pipe * +*************************************************/ +void Pipe::init() + { + pipe = 0; + default_read = 0; + locked = false; + } + +/************************************************* +* Reset the Pipe * +*************************************************/ +void Pipe::reset() + { + if(locked) + throw Invalid_State("Pipe cannot be reset while it is locked"); + destruct(pipe); + pipe = 0; + locked = false; + } + +/************************************************* +* Destroy the Pipe * +*************************************************/ +void Pipe::destruct(Filter* to_kill) + { + if(!to_kill || dynamic_cast(to_kill)) + return; + for(u32bit 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(u32bit msg) + { + if(msg >= messages.size()) + 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[], u32bit length) + { + start_msg(); + write(input, length); + end_msg(); + } + +/************************************************* +* Process a full message at once * +*************************************************/ +void Pipe::process_msg(const MemoryRegion& input) + { + process_msg(input.begin(), input.size()); + } + +/************************************************* +* Process a full message at once * +*************************************************/ +void Pipe::process_msg(const std::string& input) + { + process_msg((const byte*)input.c_str(), 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(locked) + throw Invalid_State("Pipe::start_msg: Message was already started"); + if(pipe == 0) + pipe = new Null_Filter; + find_endpoints(pipe); + pipe->new_msg(); + locked = true; + } + +/************************************************* +* End the current message * +*************************************************/ +void Pipe::end_msg() + { + if(!locked) + throw Invalid_State("Pipe::end_msg: Message was already ended"); + pipe->finish_msg(); + clear_endpoints(pipe); + if(dynamic_cast(pipe)) + { + delete pipe; + pipe = 0; + } + locked = false; + } + +/************************************************* +* Find the endpoints of the Pipe * +*************************************************/ +void Pipe::find_endpoints(Filter* f) + { + for(u32bit 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; + messages.push_back(q); + } + } + +/************************************************* +* Remove the SecureQueues attached to the Filter * +*************************************************/ +void Pipe::clear_endpoints(Filter* f) + { + if(!f) return; + for(u32bit j = 0; j != f->total_ports(); j++) + { + if(f->next[j] && dynamic_cast(f->next[j])) + f->next[j] = 0; + if(f->next[j]) + clear_endpoints(f->next[j]); + } + } + +/************************************************* +* Append a Filter to the Pipe * +*************************************************/ +void Pipe::append(Filter* filter) + { + if(locked) + throw Invalid_State("Cannot append to a Pipe while it is locked"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); + + if(!pipe) pipe = filter; + else pipe->attach(filter); + } + +/************************************************* +* Prepend a Filter to the Pipe * +*************************************************/ +void Pipe::prepend(Filter* filter) + { + if(locked) + throw Invalid_State("Cannot prepend to a Pipe while it is locked"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); + + if(pipe) filter->attach(pipe); + pipe = filter; + } + +/************************************************* +* Pop a Filter off the Pipe * +*************************************************/ +void Pipe::pop() + { + if(locked) + throw Invalid_State("Cannot pop off a Pipe while it is locked"); + if(!pipe) return; + if(pipe->total_ports() > 1) + throw Invalid_State("Cannot pop off a Filter with multiple ports"); + Filter* f = pipe; + u32bit 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 * +*************************************************/ +u32bit Pipe::message_count() const + { + return messages.size(); + } + +} --- botan/pipe.h +++ botan/pipe.h @@ -0,0 +1,91 @@ +/************************************************* +* Pipe Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PIPE_H__ +#define BOTAN_PIPE_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Pipe * +*************************************************/ +class Pipe : public DataSource + { + public: + static const u32bit MAX_MESSAGES = 0xFFFFFFF0; + static const u32bit LAST_MESSAGE = 0xFFFFFFFE; + static const u32bit DEFAULT_MESSAGE = 0xFFFFFFFF; + + void write(const byte[], u32bit); + void write(const MemoryRegion&); + void write(const std::string&); + void write(DataSource&); + void write(byte); + + void process_msg(const byte[], u32bit); + void process_msg(const MemoryRegion&); + void process_msg(const std::string&); + void process_msg(DataSource&); + + u32bit remaining(u32bit = DEFAULT_MESSAGE) const; + + u32bit read(byte[], u32bit); + u32bit read(byte[], u32bit, u32bit); + u32bit read(byte&, u32bit = DEFAULT_MESSAGE); + + SecureVector read_all(u32bit = DEFAULT_MESSAGE); + std::string read_all_as_string(u32bit = DEFAULT_MESSAGE); + + u32bit peek(byte[], u32bit, u32bit) const; + u32bit peek(byte[], u32bit, u32bit, u32bit) const; + u32bit peek(byte&, u32bit, u32bit = DEFAULT_MESSAGE) const; + + u32bit default_msg() const { return default_read; } + void set_default_msg(u32bit); + u32bit message_count() const; + bool end_of_data() const; + + void start_msg(); + void end_msg(); + + void prepend(Filter*); + void append(Filter*); + void pop(); + void reset(); + + Pipe(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + Pipe(Filter*[], u32bit); + ~Pipe(); + private: + Pipe(const Pipe&) : DataSource() {} + Pipe& operator=(const Pipe&) { return (*this); } + void init(); + void destruct(Filter*); + void find_endpoints(Filter*); + void clear_endpoints(Filter*); + class SecureQueue* get_message(const std::string&, u32bit) const; + std::vector messages; + Filter* pipe; + bool locked; + u32bit default_read; + }; + +/************************************************* +* I/O Operators for Pipe * +*************************************************/ +std::ostream& operator<<(std::ostream&, Pipe&); +std::istream& operator>>(std::istream&, Pipe&); + +} + +#endif + +#if defined(BOTAN_EXT_PIPE_UNIXFD_IO) + #include +#endif --- botan/pipe_io.cpp +++ botan/pipe_io.cpp @@ -0,0 +1,43 @@ +/************************************************* +* Pipe I/O Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Write data from a pipe into an ostream * +*************************************************/ +std::ostream& operator<<(std::ostream& stream, Pipe& pipe) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(stream.good() && pipe.remaining()) + { + u32bit got = pipe.read(buffer, buffer.size()); + stream.write((const char*)buffer.begin(), 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) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(stream.good()) + { + stream.read((char*)buffer.begin(), buffer.size()); + pipe.write(buffer, stream.gcount()); + } + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("Pipe input operator (iostream) has failed"); + return stream; + } + +} --- botan/pipe_rw.cpp +++ botan/pipe_rw.cpp @@ -0,0 +1,174 @@ +/************************************************* +* Pipe Reading/Writing Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Write into a Pipe * +*************************************************/ +SecureQueue* Pipe::get_message(const std::string& func_name, u32bit msg) const + { + if(msg == MAX_MESSAGES) + throw Invalid_State("Pipe::get_message: overflow of message counter"); + + if(msg == DEFAULT_MESSAGE) msg = default_msg(); + else if(msg == LAST_MESSAGE) msg = message_count() - 1; + + if(msg >= messages.size()) + throw Invalid_Message_Number(func_name, msg); + if(messages[msg]) + return messages[msg]; + else + throw Internal_Error("Pipe:get_message: got NULL for message #" + + to_string(msg)); + } + +/************************************************* +* Write into a Pipe * +*************************************************/ +void Pipe::write(const byte input[], u32bit length) + { + if(!locked) + throw Exception("Cannot write to a Pipe while it is unlocked"); + pipe->write(input, length); + } + +/************************************************* +* Write into a Pipe * +*************************************************/ +void Pipe::write(const MemoryRegion& input) + { + write(input.begin(), input.size()); + } + +/************************************************* +* Write a string into a Pipe * +*************************************************/ +void Pipe::write(const std::string& str) + { + write((const byte*)str.c_str(), 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) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(!source.end_of_data()) + { + u32bit got = source.read(buffer, buffer.size()); + write(buffer, got); + } + } + +/************************************************* +* Read some data from the pipe * +*************************************************/ +u32bit Pipe::read(byte output[], u32bit length, u32bit msg) + { + SecureQueue* msg_queue = get_message("read", msg); + if(msg_queue) + return msg_queue->read(output, length); + else + return 0; + } + +/************************************************* +* Read some data from the pipe * +*************************************************/ +u32bit Pipe::read(byte output[], u32bit length) + { + return read(output, length, DEFAULT_MESSAGE); + } + +/************************************************* +* Read a single byte from the pipe * +*************************************************/ +u32bit Pipe::read(byte& out, u32bit msg) + { + return read(&out, 1, msg); + } + +/************************************************* +* Return all data in the pipe * +*************************************************/ +SecureVector Pipe::read_all(u32bit msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + SecureVector buffer(remaining(msg)); + read(buffer, buffer.size(), msg); + return buffer; + } + +/************************************************* +* Return all data in the pipe as a string * +*************************************************/ +std::string Pipe::read_all_as_string(u32bit msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + SecureVector buffer(DEFAULT_BUFFERSIZE); + std::string str; + while(remaining(msg)) + { + u32bit got = read(buffer, buffer.size(), msg); + str.append((const char*)buffer.begin(), got); + } + return str; + } + +/************************************************* +* Find out how many bytes are ready to read * +*************************************************/ +u32bit Pipe::remaining(u32bit msg) const + { + SecureQueue* msg_queue = get_message("remaining", msg); + if(msg_queue) + return msg_queue->size(); + else + return 0; + } + +/************************************************* +* Peek at some data in the pipe * +*************************************************/ +u32bit Pipe::peek(byte output[], u32bit length, + u32bit offset, u32bit msg) const + { + SecureQueue* msg_queue = get_message("peek", msg); + if(msg_queue) + return msg_queue->peek(output, length, offset); + else + return 0; + } + +/************************************************* +* Peek at some data in the pipe * +*************************************************/ +u32bit Pipe::peek(byte output[], u32bit length, u32bit offset) const + { + return peek(output, length, offset, DEFAULT_MESSAGE); + } + +/************************************************* +* Peek at a byte in the pipe * +*************************************************/ +u32bit Pipe::peek(byte& out, u32bit offset, u32bit msg) const + { + return peek(&out, 1, offset, msg); + } + +} --- botan/pk_algs.cpp +++ botan/pk_algs.cpp @@ -0,0 +1,31 @@ +/************************************************* +* PK Key Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Get an PK public key object * +*************************************************/ +X509_PublicKey* get_public_key(const std::string& alg_name) + { + if(alg_name == "RSA") return new RSA_PublicKey; + else + return 0; + } + +/************************************************* +* Get an PK private key object * +*************************************************/ +PKCS8_PrivateKey* get_private_key(const std::string& alg_name) + { + if(alg_name == "RSA") return new RSA_PrivateKey; + else + return 0; + } + +} --- botan/pk_algs.h +++ botan/pk_algs.h @@ -0,0 +1,22 @@ +/************************************************* +* PK Key Factory Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PK_KEY_FACTORY_H__ +#define BOTAN_PK_KEY_FACTORY_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Get an PK key object * +*************************************************/ +X509_PublicKey* get_public_key(const std::string&); +PKCS8_PrivateKey* get_private_key(const std::string&); + +} + +#endif --- botan/pk_core.cpp +++ botan/pk_core.cpp @@ -0,0 +1,288 @@ +/************************************************* +* PK Algorithm Core Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Return a new blinding factor * +*************************************************/ +BigInt blinding_factor(u32bit modulus_size) + { + const u32bit BLINDING_BITS = Config::get_u32bit("pk/blinder_size"); + if(BLINDING_BITS == 0) + return 0; + return random_integer(std::min(modulus_size - 1, BLINDING_BITS), Nonce); + } + +} + +/************************************************* +* IF_Core Constructor * +*************************************************/ +IF_Core::IF_Core(const BigInt& e, const BigInt& n, const BigInt& d, + const BigInt& p, const BigInt& q, + const BigInt& d1, const BigInt& d2, const BigInt& c) + { + op = Engine_Core::if_op(e, n, d, p, q, d1, d2, c); + + if(d != 0) + { + BigInt k = blinding_factor(n.bits()); + if(k != 0) + blinder.initialize(power_mod(k, e, n), inverse_mod(k, n), n); + } + } + +/************************************************* +* IF_Core Copy Constructor * +*************************************************/ +IF_Core::IF_Core(const IF_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + } + +/************************************************* +* IF_Core Assignment Operator * +*************************************************/ +IF_Core& IF_Core::operator=(const IF_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + return (*this); + } + +/************************************************* +* IF Public Operation * +*************************************************/ +BigInt IF_Core::public_op(const BigInt& i) const + { + return op->public_op(i); + } + +/************************************************* +* IF Private Operation * +*************************************************/ +BigInt IF_Core::private_op(const BigInt& i) const + { + return blinder.unblind(op->private_op(blinder.blind(i))); + } + +/************************************************* +* DSA_Core Constructor * +*************************************************/ +DSA_Core::DSA_Core(const DL_Group& group, const BigInt& y, const BigInt& x) + { + op = Engine_Core::dsa_op(group, y, x); + } + +/************************************************* +* DSA_Core Copy Constructor * +*************************************************/ +DSA_Core::DSA_Core(const DSA_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + } + +/************************************************* +* DSA_Core Assignment Operator * +*************************************************/ +DSA_Core& DSA_Core::operator=(const DSA_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + return (*this); + } + +/************************************************* +* DSA Verification Operation * +*************************************************/ +bool DSA_Core::verify(const byte msg[], u32bit msg_length, + const byte sig[], u32bit sig_length) const + { + return op->verify(msg, msg_length, sig, sig_length); + } + +/************************************************* +* DSA Signature Operation * +*************************************************/ +SecureVector DSA_Core::sign(const byte in[], u32bit length, + const BigInt& k) const + { + return op->sign(in, length, k); + } + +/************************************************* +* NR_Core Constructor * +*************************************************/ +NR_Core::NR_Core(const DL_Group& group, const BigInt& y, const BigInt& x) + { + op = Engine_Core::nr_op(group, y, x); + } + +/************************************************* +* NR_Core Copy Constructor * +*************************************************/ +NR_Core::NR_Core(const NR_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + } + +/************************************************* +* NR_Core Assignment Operator * +*************************************************/ +NR_Core& NR_Core::operator=(const NR_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + return (*this); + } + +/************************************************* +* NR Verification Operation * +*************************************************/ +SecureVector NR_Core::verify(const byte in[], u32bit length) const + { + return op->verify(in, length); + } + +/************************************************* +* NR Signature Operation * +*************************************************/ +SecureVector NR_Core::sign(const byte in[], u32bit length, + const BigInt& k) const + { + return op->sign(in, length, k); + } + +/************************************************* +* ELG_Core Constructor * +*************************************************/ +ELG_Core::ELG_Core(const DL_Group& group, const BigInt& y, const BigInt& x) + { + op = Engine_Core::elg_op(group, y, x); + + p_bytes = 0; + if(x != 0) + { + const BigInt& p = group.get_p(); + p_bytes = group.get_p().bytes(); + + BigInt k = blinding_factor(p.bits()); + if(k != 0) + blinder.initialize(k, power_mod(k, x, p), p); + } + } + +/************************************************* +* ELG_Core Copy Constructor * +*************************************************/ +ELG_Core::ELG_Core(const ELG_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + p_bytes = core.p_bytes; + } + +/************************************************* +* ELG_Core Assignment Operator * +*************************************************/ +ELG_Core& ELG_Core::operator=(const ELG_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + p_bytes = core.p_bytes; + return (*this); + } + +/************************************************* +* ElGamal Encrypt Operation * +*************************************************/ +SecureVector ELG_Core::encrypt(const byte in[], u32bit length, + const BigInt& k) const + { + return op->encrypt(in, length, k); + } + +/************************************************* +* ElGamal Decrypt Operation * +*************************************************/ +SecureVector ELG_Core::decrypt(const byte in[], u32bit length) const + { + if(length != 2*p_bytes) + throw Invalid_Argument("ELG_Core::decrypt: Invalid message"); + + BigInt a(in, p_bytes); + BigInt b(in + p_bytes, p_bytes); + + return BigInt::encode(blinder.unblind(op->decrypt(blinder.blind(a), b))); + } + +/************************************************* +* DH_Core Constructor * +*************************************************/ +DH_Core::DH_Core(const DL_Group& group, const BigInt& x) + { + op = Engine_Core::dh_op(group, x); + + const BigInt& p = group.get_p(); + BigInt k = blinding_factor(p.bits()); + if(k != 0) + blinder.initialize(k, power_mod(inverse_mod(k, p), x, p), p); + } + +/************************************************* +* DH_Core Copy Constructor * +*************************************************/ +DH_Core::DH_Core(const DH_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + } + +/************************************************* +* DH_Core Assignment Operator * +*************************************************/ +DH_Core& DH_Core::operator=(const DH_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + return (*this); + } + +/************************************************* +* DH Operation * +*************************************************/ +BigInt DH_Core::agree(const BigInt& i) const + { + return blinder.unblind(op->agree(blinder.blind(i))); + } + +} --- botan/pk_core.h +++ botan/pk_core.h @@ -0,0 +1,118 @@ +/************************************************* +* PK Algorithm Core Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PK_CORE_H__ +#define BOTAN_PK_CORE_H__ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* IF Core * +*************************************************/ +class IF_Core + { + public: + BigInt public_op(const BigInt&) const; + BigInt private_op(const BigInt&) const; + + IF_Core& operator=(const IF_Core&); + + IF_Core() { op = 0; } + IF_Core(const IF_Core&); + IF_Core(const BigInt&, const BigInt&, + const BigInt& = 0, const BigInt& = 0, const BigInt& = 0, + const BigInt& = 0, const BigInt& = 0, const BigInt& = 0); + ~IF_Core() { delete op; } + private: + IF_Operation* op; + Blinder blinder; + }; + +/************************************************* +* DSA Core * +*************************************************/ +class DSA_Core + { + public: + SecureVector sign(const byte[], u32bit, const BigInt&) const; + bool verify(const byte[], u32bit, const byte[], u32bit) const; + + DSA_Core& operator=(const DSA_Core&); + + DSA_Core() { op = 0; } + DSA_Core(const DSA_Core&); + DSA_Core(const DL_Group&, const BigInt&, const BigInt& = 0); + ~DSA_Core() { delete op; } + private: + DSA_Operation* op; + }; + +/************************************************* +* NR Core * +*************************************************/ +class NR_Core + { + public: + SecureVector sign(const byte[], u32bit, const BigInt&) const; + SecureVector verify(const byte[], u32bit) const; + + NR_Core& operator=(const NR_Core&); + + NR_Core() { op = 0; } + NR_Core(const NR_Core&); + NR_Core(const DL_Group&, const BigInt&, const BigInt& = 0); + ~NR_Core() { delete op; } + private: + NR_Operation* op; + }; + +/************************************************* +* ElGamal Core * +*************************************************/ +class ELG_Core + { + public: + SecureVector encrypt(const byte[], u32bit, const BigInt&) const; + SecureVector decrypt(const byte[], u32bit) const; + + ELG_Core& operator=(const ELG_Core&); + + ELG_Core() { op = 0; } + ELG_Core(const ELG_Core&); + ELG_Core(const DL_Group&, const BigInt&, const BigInt& = 0); + ~ELG_Core() { delete op; } + private: + ELG_Operation* op; + Blinder blinder; + u32bit p_bytes; + }; + +/************************************************* +* DH Core * +*************************************************/ +class DH_Core + { + public: + BigInt agree(const BigInt&) const; + + DH_Core& operator=(const DH_Core&); + + DH_Core() { op = 0; } + DH_Core(const DH_Core&); + DH_Core(const DL_Group&, const BigInt&); + ~DH_Core() { delete op; } + private: + DH_Operation* op; + Blinder blinder; + }; + +} + +#endif --- botan/pk_filts.cpp +++ botan/pk_filts.cpp @@ -0,0 +1,113 @@ +/************************************************* +* PK Filters Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Append to the buffer * +*************************************************/ +void PK_Encryptor_Filter::write(const byte input[], u32bit length) + { + buffer.append(input, length); + } + +/************************************************* +* Encrypt the message * +*************************************************/ +void PK_Encryptor_Filter::end_msg() + { + send(cipher->encrypt(buffer, buffer.size())); + buffer.destroy(); + } + +/************************************************* +* Append to the buffer * +*************************************************/ +void PK_Decryptor_Filter::write(const byte input[], u32bit length) + { + buffer.append(input, length); + } + +/************************************************* +* Decrypt the message * +*************************************************/ +void PK_Decryptor_Filter::end_msg() + { + send(cipher->decrypt(buffer, buffer.size())); + buffer.destroy(); + } + +/************************************************* +* Add more data * +*************************************************/ +void PK_Signer_Filter::write(const byte input[], u32bit length) + { + signer->update(input, length); + } + +/************************************************* +* Sign the message * +*************************************************/ +void PK_Signer_Filter::end_msg() + { + send(signer->signature()); + } + +/************************************************* +* Add more data * +*************************************************/ +void PK_Verifier_Filter::write(const byte input[], u32bit length) + { + verifier->update(input, length); + } + +/************************************************* +* Verify the message * +*************************************************/ +void PK_Verifier_Filter::end_msg() + { + if(signature.is_empty()) + throw Exception("PK_Verifier_Filter: No signature to check against"); + bool is_valid = verifier->check_signature(signature, signature.size()); + send((is_valid ? 1 : 0)); + } + +/************************************************* +* Set the signature to check * +*************************************************/ +void PK_Verifier_Filter::set_signature(const byte sig[], u32bit length) + { + signature.set(sig, length); + } + +/************************************************* +* Set the signature to check * +*************************************************/ +void PK_Verifier_Filter::set_signature(const MemoryRegion& sig) + { + signature = sig; + } + +/************************************************* +* PK_Verifier_Filter Constructor * +*************************************************/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, const byte sig[], + u32bit length) : + verifier(v), signature(sig, length) + { + } + +/************************************************* +* PK_Verifier_Filter Constructor * +*************************************************/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, + const MemoryRegion& sig) : + verifier(v), signature(sig) + { + } + +} --- botan/pk_filts.h +++ botan/pk_filts.h @@ -0,0 +1,81 @@ +/************************************************* +* PK Filters Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PK_FILTERS_H__ +#define BOTAN_PK_FILTERS_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* PK_Encryptor Filter * +*************************************************/ +class PK_Encryptor_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + PK_Encryptor_Filter(PK_Encryptor* c) : cipher(c) {} + ~PK_Encryptor_Filter() { delete cipher; } + private: + PK_Encryptor* cipher; + SecureVector buffer; + }; + +/************************************************* +* PK_Decryptor Filter * +*************************************************/ +class PK_Decryptor_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + PK_Decryptor_Filter(PK_Decryptor* c) : cipher(c) {} + ~PK_Decryptor_Filter() { delete cipher; } + private: + PK_Decryptor* cipher; + SecureVector buffer; + }; + +/************************************************* +* PK_Signer Filter * +*************************************************/ +class PK_Signer_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + PK_Signer_Filter(PK_Signer* s) : signer(s) {} + ~PK_Signer_Filter() { delete signer; } + private: + PK_Signer* signer; + }; + +/************************************************* +* PK_Verifier Filter * +*************************************************/ +class PK_Verifier_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + + void set_signature(const byte[], u32bit); + void set_signature(const MemoryRegion&); + + PK_Verifier_Filter(PK_Verifier* v) : verifier(v) {} + PK_Verifier_Filter(PK_Verifier*, const byte[], u32bit); + PK_Verifier_Filter(PK_Verifier*, const MemoryRegion&); + ~PK_Verifier_Filter() { delete verifier; } + private: + PK_Verifier* verifier; + SecureVector signature; + }; + +} + +#endif --- botan/pk_keys.cpp +++ botan/pk_keys.cpp @@ -0,0 +1,68 @@ +/************************************************* +* PK Key Types Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Find out how much testing should be performed * +*************************************************/ +bool key_check_level(const std::string& type) + { + const std::string setting = Config::get_string("pk/test/" + type); + if(setting == "basic") + return false; + return true; + } + +} + +/************************************************* +* Default OID access * +*************************************************/ +OID PK_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 PK_Key::check_loaded_public() const + { + if(!check_key(key_check_level("public"))) + throw Invalid_Argument(algo_name() + ": Invalid public key"); + } + +/************************************************* +* Run checks on a loaded private key * +*************************************************/ +void PK_Key::check_loaded_private() const + { + if(!check_key(key_check_level("private"))) + throw Invalid_Argument(algo_name() + ": Invalid private key"); + } + +/************************************************* +* Run checks on a generated private key * +*************************************************/ +void PK_Key::check_generated_private() const + { + if(!check_key(key_check_level("private_gen"))) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +} --- botan/pk_keys.h +++ botan/pk_keys.h @@ -0,0 +1,100 @@ +/************************************************* +* PK Key Types Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PK_KEYS_H__ +#define BOTAN_PK_KEYS_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* Generic PK Key * +*************************************************/ +class PK_Key + { + public: + virtual std::string algo_name() const = 0; + + virtual OID get_oid() const; + virtual u32bit max_input_bits() const { return 0; } + virtual bool check_key(bool) const { return true; } + virtual u32bit message_parts() const { return 1; } + virtual u32bit message_part_size() const { return 0; } + virtual ~PK_Key() {} + protected: + void check_loaded_public() const; + void check_loaded_private() const; + void check_generated_private() const; + }; + +/************************************************* +* PK Encrypting Key * +*************************************************/ +class PK_Encrypting_Key : public virtual PK_Key + { + public: + virtual SecureVector encrypt(const byte[], u32bit) const = 0; + virtual ~PK_Encrypting_Key() {} + }; + +/************************************************* +* PK Decrypting Key * +*************************************************/ +class PK_Decrypting_Key : public virtual PK_Key + { + public: + virtual SecureVector decrypt(const byte[], u32bit) const = 0; + virtual ~PK_Decrypting_Key() {} + }; + +/************************************************* +* PK Signing Key * +*************************************************/ +class PK_Signing_Key : public virtual PK_Key + { + public: + virtual SecureVector sign(const byte[], u32bit) const = 0; + virtual ~PK_Signing_Key() {} + }; + +/************************************************* +* PK Verifying Key, Message Recovery Version * +*************************************************/ +class PK_Verifying_with_MR_Key : public virtual PK_Key + { + public: + virtual SecureVector verify(const byte[], u32bit) const = 0; + virtual ~PK_Verifying_with_MR_Key() {} + }; + +/************************************************* +* PK Verifying Key, No Message Recovery Version * +*************************************************/ +class PK_Verifying_wo_MR_Key : public virtual PK_Key + { + public: + virtual bool verify(const byte[], u32bit, + const byte[], u32bit) const = 0; + virtual ~PK_Verifying_wo_MR_Key() {} + }; + +/************************************************* +* PK Secret Value Derivation Key * +*************************************************/ +class PK_Key_Agreement_Key : public virtual PK_Key + { + public: + virtual SecureVector derive_key(const byte[], u32bit) const = 0; + virtual MemoryVector public_value() const = 0; + virtual ~PK_Key_Agreement_Key() {} + }; + +typedef PK_Key_Agreement_Key PK_KA_Key; + +} + +#endif --- botan/pk_ops.h +++ botan/pk_ops.h @@ -0,0 +1,79 @@ +/************************************************* +* Public Key Operations Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PK_OPS_H__ +#define BOTAN_PK_OPS_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* IF Operation * +*************************************************/ +class IF_Operation + { + public: + virtual BigInt public_op(const BigInt&) const = 0; + virtual BigInt private_op(const BigInt&) const = 0; + virtual IF_Operation* clone() const = 0; + virtual ~IF_Operation() {} + }; + +/************************************************* +* DSA Operation * +*************************************************/ +class DSA_Operation + { + public: + virtual bool verify(const byte[], u32bit, + const byte[], u32bit) const = 0; + virtual SecureVector sign(const byte[], u32bit, + const BigInt&) const = 0; + virtual DSA_Operation* clone() const = 0; + virtual ~DSA_Operation() {} + }; + +/************************************************* +* NR Operation * +*************************************************/ +class NR_Operation + { + public: + virtual SecureVector verify(const byte[], u32bit) const = 0; + virtual SecureVector sign(const byte[], u32bit, + const BigInt&) const = 0; + virtual NR_Operation* clone() const = 0; + virtual ~NR_Operation() {} + }; + +/************************************************* +* ElGamal Operation * +*************************************************/ +class ELG_Operation + { + public: + virtual SecureVector encrypt(const byte[], u32bit, + const BigInt&) const = 0; + virtual BigInt decrypt(const BigInt&, const BigInt&) const = 0; + virtual ELG_Operation* clone() const = 0; + virtual ~ELG_Operation() {} + }; + +/************************************************* +* DH Operation * +*************************************************/ +class DH_Operation + { + public: + virtual BigInt agree(const BigInt&) const = 0; + virtual DH_Operation* clone() const = 0; + virtual ~DH_Operation() {} + }; + +} + +#endif --- botan/pk_util.cpp +++ botan/pk_util.cpp @@ -0,0 +1,116 @@ +/************************************************* +* PK Utility Classes Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Encode a message * +*************************************************/ +SecureVector EME::encode(const byte msg[], u32bit msg_len, + u32bit key_bits) const + { + return pad(msg, msg_len, key_bits); + } + +/************************************************* +* Encode a message * +*************************************************/ +SecureVector EME::encode(const MemoryRegion& msg, + u32bit key_bits) const + { + return pad(msg, msg.size(), key_bits); + } + +/************************************************* +* Decode a message * +*************************************************/ +SecureVector EME::decode(const byte msg[], u32bit msg_len, + u32bit key_bits) const + { + return unpad(msg, msg_len, key_bits); + } + +/************************************************* +* Decode a message * +*************************************************/ +SecureVector EME::decode(const MemoryRegion& msg, + u32bit key_bits) const + { + return unpad(msg, msg.size(), key_bits); + } + +/************************************************* +* Default signature decoding * +*************************************************/ +bool EMSA::verify(const MemoryRegion& coded, + const MemoryRegion& raw, + u32bit key_bits) throw() + { + try { + return (coded == encoding_of(raw, key_bits)); + } + catch(Invalid_Argument) + { + return false; + } + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector KDF::derive_key(u32bit key_len, + const MemoryRegion& secret, + const std::string& salt) const + { + return derive_key(key_len, secret, secret.size(), + (const byte*)salt.c_str(), salt.length()); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector KDF::derive_key(u32bit key_len, + const MemoryRegion& secret, + const byte salt[], u32bit salt_len) const + { + return derive_key(key_len, secret.begin(), secret.size(), + salt, salt_len); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector KDF::derive_key(u32bit key_len, + const MemoryRegion& secret, + const MemoryRegion& salt) const + { + return derive_key(key_len, secret.begin(), secret.size(), + salt.begin(), salt.size()); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector KDF::derive_key(u32bit key_len, + const byte secret[], u32bit secret_len, + const std::string& salt) const + { + return derive_key(key_len, secret, secret_len, + (const byte*)salt.c_str(), salt.length()); + } + +/************************************************* +* Derive a key * +*************************************************/ +SecureVector KDF::derive_key(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte salt[], u32bit salt_len) const + { + return derive(key_len, secret, secret_len, salt, salt_len); + } + +} --- botan/pk_util.h +++ botan/pk_util.h @@ -0,0 +1,82 @@ +/************************************************* +* PK Utility Classes Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PUBKEY_UTIL_H__ +#define BOTAN_PUBKEY_UTIL_H__ + +#include + +namespace Botan { + +/************************************************* +* Encoding Method for Encryption * +*************************************************/ +class EME + { + public: + virtual u32bit maximum_input_size(u32bit) const = 0; + SecureVector encode(const byte[], u32bit, u32bit) const; + SecureVector encode(const MemoryRegion&, u32bit) const; + SecureVector decode(const byte[], u32bit, u32bit) const; + SecureVector decode(const MemoryRegion&, u32bit) const; + + virtual ~EME() {} + private: + virtual SecureVector pad(const byte[], u32bit, u32bit) const = 0; + virtual SecureVector unpad(const byte[], u32bit, u32bit) const = 0; + }; + +/************************************************* +* Encoding Method for Signatures, Appendix * +*************************************************/ +class EMSA + { + public: + virtual void update(const byte[], u32bit) = 0; + virtual SecureVector raw_data() = 0; + virtual SecureVector encoding_of(const MemoryRegion&, + u32bit) = 0; + virtual bool verify(const MemoryRegion&, const MemoryRegion&, + u32bit) throw(); + virtual ~EMSA() {} + }; + +/************************************************* +* Key Derivation Function * +*************************************************/ +class KDF + { + public: + SecureVector derive_key(u32bit, const MemoryRegion&, + const std::string& = "") const; + SecureVector derive_key(u32bit, const MemoryRegion&, + const MemoryRegion&) const; + SecureVector derive_key(u32bit, const MemoryRegion&, + const byte[], u32bit) const; + + SecureVector derive_key(u32bit, const byte[], u32bit, + const std::string& = "") const; + SecureVector derive_key(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + + virtual ~KDF() {} + private: + virtual SecureVector derive(u32bit, const byte[], u32bit, + const byte[], u32bit) const = 0; + }; + +/************************************************* +* Mask Generation Function * +*************************************************/ +class MGF + { + public: + virtual void mask(const byte[], u32bit, byte[], u32bit) const = 0; + virtual ~MGF() {} + }; + +} + +#endif --- botan/pkcs10.cpp +++ botan/pkcs10.cpp @@ -0,0 +1,226 @@ +/************************************************* +* PKCS #10 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* PKCS10_Request Constructor * +*************************************************/ +PKCS10_Request::PKCS10_Request(DataSource& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + is_ca = false; + max_path_len = 0; + constraints_value = NO_CONSTRAINTS; + + do_decode(); + } + +/************************************************* +* PKCS10_Request Constructor * +*************************************************/ +PKCS10_Request::PKCS10_Request(const std::string& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + is_ca = false; + max_path_len = 0; + + do_decode(); + } + +/************************************************* +* Deocde the CertificateRequestInfo * +*************************************************/ +void PKCS10_Request::force_decode() + { + BER_Decoder cert_req_info(tbs_bits); + + u32bit version; + BER::decode(cert_req_info, version); + if(version != 0) + throw Decoding_Error("Unknown version code in PKCS #10 request: " + + to_string(version)); + + BER::decode(cert_req_info, dn); + + 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); + pub_key = DER::put_in_sequence(public_key.value); + + 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; + BER::decode(attributes, 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(); + + std::vector emails = dn.get_attribute("PKCS9.EmailAddress"); + for(u32bit j = 0; j != emails.size(); j++) + subject_alt.add_attribute("RFC822", emails[j]); + + X509_Code sig_check = X509_Store::check_sig(*this, subject_public_key()); + if(sig_check != VERIFIED) + 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; + BER::decode(value, email); + subject_alt.add_attribute("RFC822", email.value()); + } + else if(attr.oid == OIDS::lookup("PKCS9.ChallengePassword")) + { + ASN1_String challenge_password; + BER::decode(value, challenge_password); + challenge = challenge_password.value(); + } + else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest")) + { + BER_Decoder sequence = BER::get_subsequence(value); + + while(sequence.more_items()) + { + Extension extn; + BER::decode(sequence, extn); + handle_v3_extension(extn); + } + sequence.verify_end(); + } + } + +/************************************************* +* Decode a requested X.509v3 extension * +*************************************************/ +void PKCS10_Request::handle_v3_extension(const Extension& extn) + { + BER_Decoder value(extn.value); + + if(extn.oid == OIDS::lookup("X509v3.KeyUsage")) + BER::decode(value, constraints_value); + else if(extn.oid == OIDS::lookup("X509v3.ExtendedKeyUsage")) + { + BER_Decoder key_usage = BER::get_subsequence(value); + while(key_usage.more_items()) + { + OID usage_oid; + BER::decode(key_usage, usage_oid); + ex_constraints_list.push_back(usage_oid); + } + } + else if(extn.oid == OIDS::lookup("X509v3.BasicConstraints")) + { + BER_Decoder constraints = BER::get_subsequence(value); + BER::decode_optional(constraints, is_ca, BOOLEAN, UNIVERSAL, false); + BER::decode_optional(constraints, max_path_len, + INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT); + } + else if(extn.oid == OIDS::lookup("X509v3.SubjectAlternativeName")) + BER::decode(value, subject_alt); + else + return; + + value.verify_end(); + } + +/************************************************* +* Return the public key of the requestor * +*************************************************/ +MemoryVector PKCS10_Request::raw_public_key() const + { + return pub_key; + } + +/************************************************* +* Return the public key of the requestor * +*************************************************/ +X509_PublicKey* PKCS10_Request::subject_public_key() const + { + return X509::load_key(pub_key); + } + +/************************************************* +* Return the name of the requestor * +*************************************************/ +X509_DN PKCS10_Request::subject_dn() const + { + return dn; + } + +/************************************************* +* Return the alternative names of the requestor * +*************************************************/ +AlternativeName PKCS10_Request::subject_alt_name() const + { + return subject_alt; + } + +/************************************************* +* Return the challenge password (if any) * +*************************************************/ +std::string PKCS10_Request::challenge_password() const + { + return challenge; + } + +/************************************************* +* Return the key constraints (if any) * +*************************************************/ +Key_Constraints PKCS10_Request::constraints() const + { + return constraints_value; + } + +/************************************************* +* Return the extendend key constraints (if any) * +*************************************************/ +std::vector PKCS10_Request::ex_constraints() const + { + return ex_constraints_list; + } + +/************************************************* +* Return is a CA certificate is requested * +*************************************************/ +bool PKCS10_Request::is_CA() const + { + return is_ca; + } + +/************************************************* +* Return the desired path limit (if any) * +*************************************************/ +u32bit PKCS10_Request::path_limit() const + { + return max_path_len; + } + +} --- botan/pkcs10.h +++ botan/pkcs10.h @@ -0,0 +1,53 @@ +/************************************************* +* PKCS #10 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PKCS10_H__ +#define BOTAN_PKCS10_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* PKCS #10 Certificate Request * +*************************************************/ +class PKCS10_Request : public X509_Object + { + public: + X509_PublicKey* subject_public_key() const; + + MemoryVector raw_public_key() const; + X509_DN subject_dn() const; + AlternativeName subject_alt_name() const; + Key_Constraints constraints() const; + std::vector ex_constraints() const; + + bool is_CA() const; + u32bit path_limit() const; + + std::string challenge_password() const; + + PKCS10_Request(DataSource&); + PKCS10_Request(const std::string&); + private: + void force_decode(); + void handle_attribute(const Attribute&); + void handle_v3_extension(const Extension&); + + MemoryVector pub_key; + X509_DN dn; + AlternativeName subject_alt; + std::string challenge; + Key_Constraints constraints_value; + std::vector ex_constraints_list; + bool is_ca; + u32bit max_path_len; + }; + +} + +#endif --- botan/pkcs8.cpp +++ botan/pkcs8.cpp @@ -0,0 +1,340 @@ +/************************************************* +* PKCS #8 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace PKCS8 { + +namespace { + +/************************************************* +* Get info from an RAW_BER pkcs8 key. * +* Whether it is encrypted will be determined, * +* returned in is_encrypted. * +*************************************************/ +SecureVector PKCS8_maybe_enc_extract(DataSource& source, + AlgorithmIdentifier& alg_id, + bool& is_encrypted) + { + SecureVector enc_pkcs8_key; + u32bit version = 0; + + is_encrypted = false; + try { + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + + try { + BER::decode(sequence, version); + } + catch(Decoding_Error) { + is_encrypted = true; + } + + BER::decode(sequence, alg_id); + BER::decode(sequence, enc_pkcs8_key, OCTET_STRING); + if (is_encrypted) + sequence.discard_remaining(); + sequence.verify_end(); + } + catch(Decoding_Error) + { + throw PKCS8_Exception("Private key decoding failed"); + } + + if (version != 0) + throw Decoding_Error("PKCS #8: Unknown version number"); + + + return enc_pkcs8_key; + } + +/************************************************* +* Get info from an EncryptedPrivateKeyInfo * +*************************************************/ +SecureVector PKCS8_extract(DataSource& source, + AlgorithmIdentifier& alg_id) + { + SecureVector enc_pkcs8_key; + + try { + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, alg_id); + BER::decode(sequence, enc_pkcs8_key, OCTET_STRING); + sequence.verify_end(); + } + catch(Decoding_Error) + { + throw PKCS8_Exception("Private key decoding failed"); + } + + return enc_pkcs8_key; + } + +/************************************************* +* PEM decode and/or decrypt a private key * +*************************************************/ +SecureVector PKCS8_decode(DataSource& source, const User_Interface& ui, + AlgorithmIdentifier& pk_alg_id) + { + AlgorithmIdentifier pbe_alg_id; + SecureVector key_data, key; + bool is_encrypted = true; + + try { + if(BER::maybe_BER(source) && !PEM_Code::matches(source)) + { + key_data = PKCS8_maybe_enc_extract(source, pbe_alg_id, is_encrypted); + if(key_data.is_empty()) + throw Decoding_Error("PKCS #8 private key decoding failed"); + if(!is_encrypted) + { + pk_alg_id = pbe_alg_id; + return key_data; // just plain unencrypted BER + } + } + 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 source(key_data); + key_data = PKCS8_extract(source, pbe_alg_id); + } + else + throw PKCS8_Exception("Unknown PEM label " + label); + } + + if(key_data.is_empty()) + throw PKCS8_Exception("No key data found"); + } + catch(Decoding_Error) + { + throw Decoding_Error("PKCS #8 private key decoding failed"); + } + + if(!is_encrypted) + key = key_data; + + u32bit tries = 0; + while(true) + { + try { + if(tries >= Config::get_u32bit("base/pkcs8_tries")) + break; + + if(is_encrypted) + { + DataSource_Memory params(pbe_alg_id.parameters); + PBE* pbe = get_pbe(pbe_alg_id.oid, params); + + User_Interface::UI_Result result = User_Interface::OK; + const std::string passphrase = + ui.get_passphrase("PKCS #8 private key", source.id(), result); + + if(result == User_Interface::CANCEL_ACTION) + break; + + pbe->set_key(passphrase); + Pipe decryptor(pbe); + decryptor.process_msg(key_data, key_data.size()); + key = decryptor.read_all(); + } + + u32bit version; + BER_Decoder decoder(key); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, version); + if(version != 0) + throw Decoding_Error("PKCS #8: Unknown version number"); + + BER::decode(sequence, pk_alg_id); + BER::decode(sequence, key, OCTET_STRING); + sequence.discard_remaining(); + sequence.verify_end(); + + break; + } + catch(Decoding_Error) + { + tries++; + } + } + + if(key.is_empty()) + throw Decoding_Error("PKCS #8 private key decoding failed"); + return key; + } + +} + +/************************************************* +* DER or PEM encode a PKCS #8 private key * +*************************************************/ +void encode(const PKCS8_PrivateKey& key, Pipe& pipe, X509_Encoding encoding) + { + AlgorithmIdentifier alg_id(key.get_oid(), key.DER_encode_params()); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 0); + DER::encode(encoder, alg_id); + DER::encode(encoder, key.DER_encode_priv(), OCTET_STRING); + encoder.end_sequence(); + + if(encoding == PEM) + pipe.write(PEM_Code::encode(encoder.get_contents(), "PRIVATE KEY")); + else + pipe.write(encoder.get_contents()); + } + +/************************************************* +* Encode and encrypt a PKCS #8 private key * +*************************************************/ +void encrypt_key(const PKCS8_PrivateKey& key, Pipe& pipe, + const std::string& pass, const std::string& pbe_algo, + X509_Encoding encoding) + { + const std::string DEFAULT_PBE = Config::get_string("base/default_pbe"); + + Pipe raw_key; + raw_key.start_msg(); + encode(key, raw_key, RAW_BER); + raw_key.end_msg(); + + PBE* pbe = get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)); + pbe->set_key(pass); + AlgorithmIdentifier pbe_id(pbe->get_oid(), pbe->encode_params()); + Pipe key_encrytor(pbe); + key_encrytor.process_msg(raw_key); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, pbe_id); + DER::encode(encoder, key_encrytor.read_all(), OCTET_STRING); + encoder.end_sequence(); + SecureVector enc_key = encoder.get_contents(); + + if(encoding == PEM) + pipe.write(PEM_Code::encode(enc_key, "ENCRYPTED PRIVATE KEY")); + else + pipe.write(enc_key); + } + +/************************************************* +* PEM encode a PKCS #8 private key * +*************************************************/ +std::string PEM_encode(const PKCS8_PrivateKey& key) + { + Pipe pem; + pem.start_msg(); + encode(key, pem, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/************************************************* +* Encrypt and PEM encode a PKCS #8 private key * +*************************************************/ +std::string PEM_encode(const PKCS8_PrivateKey& key, const std::string& pass, + const std::string& pbe_algo) + { + if(pass == "") + return PEM_encode(key); + + Pipe pem; + pem.start_msg(); + encrypt_key(key, pem, pass, pbe_algo, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/************************************************* +* Extract a private key and return it * +*************************************************/ +PKCS8_PrivateKey* load_key(DataSource& source, const User_Interface& ui) + { + AlgorithmIdentifier alg_id; + + SecureVector pkcs8_key = PKCS8_decode(source, ui, alg_id); + + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw PKCS8_Exception("Unknown algorithm OID: " + + alg_id.oid.as_string()); + + std::auto_ptr key(get_private_key(alg_name)); + + if(!key.get()) + throw PKCS8_Exception("Unknown PK algorithm/OID: " + alg_name + ", " + + alg_id.oid.as_string()); + + Pipe output; + output.process_msg(alg_id.parameters); + output.process_msg(pkcs8_key); + key->BER_decode_params(output); + output.set_default_msg(1); + key->BER_decode_priv(output); + + return key.release(); + } + +/************************************************* +* Extract a private key and return it * +*************************************************/ +PKCS8_PrivateKey* load_key(const std::string& fsname, const User_Interface& ui) + { + DataSource_Stream source(fsname); + return PKCS8::load_key(source, ui); + } + +/************************************************* +* Extract a private key and return it * +*************************************************/ +PKCS8_PrivateKey* load_key(DataSource& source, const std::string& pass) + { + return PKCS8::load_key(source, User_Interface(pass)); + } + +/************************************************* +* Extract a private key and return it * +*************************************************/ +PKCS8_PrivateKey* load_key(const std::string& fsname, const std::string& pass) + { + DataSource_Stream source(fsname); + return PKCS8::load_key(source, User_Interface(pass)); + } + +/************************************************* +* Make a copy of this private key * +*************************************************/ +PKCS8_PrivateKey* copy_key(const PKCS8_PrivateKey& key) + { + Pipe bits; + + bits.start_msg(); + PKCS8::encode(key, bits); + bits.end_msg(); + + DataSource_Memory source(bits.read_all()); + return PKCS8::load_key(source); + } + +} + +} --- botan/pkcs8.h +++ botan/pkcs8.h @@ -0,0 +1,59 @@ +/************************************************* +* PKCS #8 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PKCS8_H__ +#define BOTAN_PKCS8_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* PKCS #8 Private Key * +*************************************************/ +class PKCS8_PrivateKey : public virtual X509_PublicKey + { + public: + virtual SecureVector DER_encode_priv() const = 0; + virtual void BER_decode_priv(DataSource&) = 0; + virtual ~PKCS8_PrivateKey() {} + }; + +/************************************************* +* PKCS #8 General Exception * +*************************************************/ +struct PKCS8_Exception : public Decoding_Error + { + PKCS8_Exception(const std::string& error) : + Decoding_Error("PKCS #8: " + error) {} + }; + +namespace PKCS8 { + +/************************************************* +* PKCS #8 Private Key Encoding/Decoding * +*************************************************/ +void encode(const PKCS8_PrivateKey&, Pipe&, X509_Encoding = PEM); +void encrypt_key(const PKCS8_PrivateKey&, Pipe&, const std::string&, + const std::string& = "", X509_Encoding = PEM); + +std::string PEM_encode(const PKCS8_PrivateKey&); +std::string PEM_encode(const PKCS8_PrivateKey&, const std::string&, + const std::string& = ""); + +PKCS8_PrivateKey* load_key(DataSource&, const User_Interface&); +PKCS8_PrivateKey* load_key(DataSource&, const std::string& = ""); + +PKCS8_PrivateKey* load_key(const std::string&, const User_Interface&); +PKCS8_PrivateKey* load_key(const std::string&, const std::string& = ""); + +PKCS8_PrivateKey* copy_key(const PKCS8_PrivateKey&); + +} + +} + +#endif --- botan/policy.cpp +++ botan/policy.cpp @@ -0,0 +1,227 @@ +/************************************************* +* Default Policy Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* OID loading helper function * +*************************************************/ +void add_oid(const std::string& oid_str, const std::string& name) + { + OIDS::add_oid(OID(oid_str), name); + } + +} + +/************************************************* +* Load all of the default OIDs * +*************************************************/ +void add_default_oids() + { + add_oid("1.2.840.113549.1.1.1", "RSA"); + add_oid("2.5.8.1.1", "RSA"); + add_oid("1.2.840.10040.4.1", "DSA"); + add_oid("1.2.840.10046.2.1", "DH"); + add_oid("1.3.6.1.4.1.3029.1.2.1", "ELG"); + + add_oid("1.3.14.3.2.7", "DES/CBC"); + add_oid("1.2.840.113549.3.7", "TripleDES/CBC"); + add_oid("1.2.840.113549.3.2", "RC2/CBC"); + add_oid("1.2.840.113533.7.66.10", "CAST-128/CBC"); + add_oid("2.16.840.1.101.3.4.1.2", "AES-128/CBC"); + add_oid("2.16.840.1.101.3.4.1.22", "AES-192/CBC"); + add_oid("2.16.840.1.101.3.4.1.42", "AES-256/CBC"); + + add_oid("1.2.840.113549.2.5", "MD5"); + add_oid("1.3.14.3.2.26", "SHA-160"); + + add_oid("1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES"); + add_oid("1.2.840.113549.1.9.16.3.7", "KeyWrap.RC2"); + add_oid("1.2.840.113533.7.66.15", "KeyWrap.CAST-128"); + add_oid("2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128"); + add_oid("2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192"); + add_oid("2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256"); + + add_oid("1.2.840.113549.1.9.16.3.8", "Compression.Zlib"); + + add_oid("1.2.840.113549.1.1.1", "RSA/EME-PKCS1-v1_5"); + add_oid("1.2.840.113549.1.1.2", "RSA/EMSA3(MD2)"); + add_oid("1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)"); + add_oid("1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)"); + add_oid("1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)"); + add_oid("1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)"); + add_oid("1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)"); + add_oid("1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)"); + add_oid("1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)"); + + add_oid("2.5.4.3", "X520.CommonName"); + add_oid("2.5.4.4", "X520.Surname"); + add_oid("2.5.4.5", "X520.SerialNumber"); + add_oid("2.5.4.6", "X520.Country"); + add_oid("2.5.4.7", "X520.Locality"); + add_oid("2.5.4.8", "X520.State"); + add_oid("2.5.4.10", "X520.Organization"); + add_oid("2.5.4.11", "X520.OrganizationalUnit"); + add_oid("2.5.4.12", "X520.Title"); + add_oid("2.5.4.42", "X520.GivenName"); + add_oid("2.5.4.43", "X520.Initials"); + add_oid("2.5.4.44", "X520.GenerationalQualifier"); + add_oid("2.5.4.46", "X520.DNQualifier"); + add_oid("2.5.4.65", "X520.Pseudonym"); + + add_oid("1.2.840.113549.1.5.12", "PKCS5.PBKDF2"); + add_oid("1.2.840.113549.1.5.1", "PBE-PKCS5v15(MD2,DES/CBC)"); + add_oid("1.2.840.113549.1.5.4", "PBE-PKCS5v15(MD2,RC2/CBC)"); + add_oid("1.2.840.113549.1.5.3", "PBE-PKCS5v15(MD5,DES/CBC)"); + add_oid("1.2.840.113549.1.5.6", "PBE-PKCS5v15(MD5,RC2/CBC)"); + add_oid("1.2.840.113549.1.5.10", "PBE-PKCS5v15(SHA-160,DES/CBC)"); + add_oid("1.2.840.113549.1.5.11", "PBE-PKCS5v15(SHA-160,RC2/CBC)"); + add_oid("1.2.840.113549.1.5.13", "PBE-PKCS5v20"); + + add_oid("1.2.840.113549.1.9.1", "PKCS9.EmailAddress"); + add_oid("1.2.840.113549.1.9.2", "PKCS9.UnstructuredName"); + add_oid("1.2.840.113549.1.9.3", "PKCS9.ContentType"); + add_oid("1.2.840.113549.1.9.4", "PKCS9.MessageDigest"); + add_oid("1.2.840.113549.1.9.7", "PKCS9.ChallengePassword"); + add_oid("1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest"); + + add_oid("1.2.840.113549.1.7.1", "CMS.DataContent"); + add_oid("1.2.840.113549.1.7.2", "CMS.SignedData"); + add_oid("1.2.840.113549.1.7.3", "CMS.EnvelopedData"); + add_oid("1.2.840.113549.1.7.5", "CMS.DigestedData"); + add_oid("1.2.840.113549.1.7.6", "CMS.EncryptedData"); + add_oid("1.2.840.113549.1.9.16.1.2", "CMS.AuthenticatedData"); + add_oid("1.2.840.113549.1.9.16.1.9", "CMS.CompressedData"); + + add_oid("2.5.29.14", "X509v3.SubjectKeyIdentifier"); + add_oid("2.5.29.15", "X509v3.KeyUsage"); + add_oid("2.5.29.17", "X509v3.SubjectAlternativeName"); + add_oid("2.5.29.18", "X509v3.IssuerAlternativeName"); + add_oid("2.5.29.19", "X509v3.BasicConstraints"); + add_oid("2.5.29.20", "X509v3.CRLNumber"); + add_oid("2.5.29.21", "X509v3.ReasonCode"); + add_oid("2.5.29.23", "X509v3.HoldInstructionCode"); + add_oid("2.5.29.24", "X509v3.InvalidityDate"); + add_oid("2.5.29.32", "X509v3.CertificatePolicies"); + add_oid("2.5.29.35", "X509v3.AuthorityKeyIdentifier"); + add_oid("2.5.29.36", "X509v3.PolicyConstraints"); + add_oid("2.5.29.37", "X509v3.ExtendedKeyUsage"); + + add_oid("2.5.29.32.0", "X509v3.AnyPolicy"); + + add_oid("1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth"); + add_oid("1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth"); + add_oid("1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning"); + add_oid("1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection"); + add_oid("1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem"); + add_oid("1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel"); + add_oid("1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser"); + add_oid("1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping"); + add_oid("1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning"); + } + +/************************************************* +* Load the list of default aliases * +*************************************************/ +void add_default_aliases() + { + add_alias("OpenPGP.Cipher.1", "IDEA"); + add_alias("OpenPGP.Cipher.2", "TripleDES"); + add_alias("OpenPGP.Cipher.3", "CAST-128"); + add_alias("OpenPGP.Cipher.4", "Blowfish"); + add_alias("OpenPGP.Cipher.5", "SAFER-SK(13)"); + add_alias("OpenPGP.Cipher.7", "AES-128"); + add_alias("OpenPGP.Cipher.8", "AES-192"); + add_alias("OpenPGP.Cipher.9", "AES-256"); + add_alias("OpenPGP.Cipher.10", "Twofish"); + + add_alias("OpenPGP.Digest.1", "MD5"); + add_alias("OpenPGP.Digest.2", "SHA-1"); + add_alias("OpenPGP.Digest.3", "RIPEMD-160"); + add_alias("OpenPGP.Digest.5", "MD2"); + add_alias("OpenPGP.Digest.6", "Tiger(24,3)"); + add_alias("OpenPGP.Digest.7", "HAVAL(20,5)"); + add_alias("OpenPGP.Digest.8", "SHA-256"); + + add_alias("TLS.Digest.0", "Parallel(MD5,SHA-1)"); + + add_alias("EME-PKCS1-v1_5", "PKCS1v15"); + add_alias("OAEP-MGF1", "EME1"); + add_alias("EME-OAEP", "EME1"); + add_alias("X9.31", "EMSA2"); + add_alias("EMSA-PKCS1-v1_5", "EMSA3"); + add_alias("PSS-MGF1", "EMSA4"); + add_alias("EMSA-PSS", "EMSA4"); + + add_alias("Rijndael", "AES"); + add_alias("3DES", "TripleDES"); + add_alias("DES-EDE", "TripleDES"); + add_alias("CAST5", "CAST-128"); + add_alias("SHA1", "SHA-160"); + add_alias("SHA-1", "SHA-160"); + add_alias("SEAL", "SEAL-3.0-BE"); + add_alias("MARK-4", "ARC4(256)"); + } + +namespace Init { + +/************************************************* +* Set the default options * +*************************************************/ +void set_default_options() + { + Config::set("base/memory_chunk", "32*1024"); + Config::set("base/default_pbe", "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"); + Config::set("base/pkcs8_tries", "3"); + + Config::set("pk/blinder_size", "64"); + Config::set("pk/test/public", "basic"); + Config::set("pk/test/private", "basic"); + Config::set("pk/test/private_gen", "all"); + + Config::set("pem/search", "4*1024"); + Config::set("pem/forgive", "8"); + Config::set("pem/width", "64"); + + Config::set("rng/min_entropy", "384", false); + Config::set("rng/es_files", "/dev/urandom:/dev/random"); + Config::set("rng/egd_path", "/var/run/egd-pool:/dev/egd-pool"); + Config::set("rng/ms_capi_prov_type", "INTEL_SEC:RSA_FULL"); + Config::set("rng/unix_path", "/usr/ucb:/usr/etc:/etc"); + + Config::set("x509/validity_slack", "24h"); + Config::set("x509/v1_assume_ca", "false"); + Config::set("x509/cache_verify_results", "30m"); + + Config::set("x509/ca/allow_ca", "false"); + Config::set("x509/ca/basic_constraints", "always"); + Config::set("x509/ca/default_expire", "1y"); + Config::set("x509/ca/signing_offset", "30s"); + Config::set("x509/ca/rsa_hash", "SHA-1"); + Config::set("x509/ca/str_type", "latin1"); + + Config::set("x509/crl/unknown_critical", "ignore"); + Config::set("x509/crl/next_update", "7d"); + + Config::set("x509/exts/basic_constraints", "critical"); + Config::set("x509/exts/subject_key_id", "yes"); + Config::set("x509/exts/authority_key_id", "yes"); + Config::set("x509/exts/subject_alternative_name", "yes"); + Config::set("x509/exts/issuer_alternative_name", "yes"); + Config::set("x509/exts/key_usage", "critical"); + Config::set("x509/exts/extended_key_usage", "yes"); + Config::set("x509/exts/crl_number", "yes"); + } + +} + +} --- botan/pow_mod.cpp +++ botan/pow_mod.cpp @@ -0,0 +1,142 @@ +/************************************************* +* Modular Exponentiation Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Exponentiation Window Size * +*************************************************/ +u32bit window_size(u32bit exp_bits) + { + struct mapping { u32bit bits; u32bit window_size; }; + + static const mapping wsize[] = { + { 2048, 7 }, + { 1024, 6 }, + { 256, 5 }, + { 128, 4 }, + { 64, 3 }, + { 0, 0 } + }; + + for(u32bit j = 0; wsize[j].bits; j++) + { + if(exp_bits >= wsize[j].bits) + return wsize[j].window_size; + } + return 1; + } + +/************************************************* +* Left-to-Right Binary Modular Exponentiation * +*************************************************/ +BigInt power_mod_l2r(const BigInt& basex, const BigInt& exp, + ModularReducer* reducer) + { + const BigInt base = reducer->convert_in(basex); + const u32bit exp_bits = exp.bits(); + + BigInt x = reducer->convert_in(1); + for(u32bit j = exp_bits; j > 0; j--) + { + x = reducer->square(x); + if(exp.get_bit(j-1)) + x = reducer->multiply(x, base); + } + return reducer->convert_out(x); + } + +/************************************************* +* Modular Exponentiation with g = 2 * +*************************************************/ +BigInt power_mod_g2(const BigInt& exp, ModularReducer* reducer) + { + if(reducer->must_convert()) + throw Internal_Error("power_mod_g2: Can't use this reducer"); + + const u32bit exp_bits = exp.bits(); + BigInt x = 1; + for(u32bit j = exp_bits; j > 0; j--) + { + x = reducer->square(x); + if(exp.get_bit(j-1)) + { + x <<= 1; + x = reducer->reduce(x); + } + } + return x; + } + +/************************************************* +* Window Modular Exponentiation * +*************************************************/ +BigInt power_mod_window(const BigInt& base, const BigInt& exp, + ModularReducer* reducer, u32bit window_bits) + { + if(window_bits < 2) + throw Internal_Error("power_mod_window: Window size too small"); + + std::vector g((1 << window_bits) - 1); + + g[0] = reducer->convert_in(base); + for(u32bit j = 1; j != g.size(); j++) + g[j] = reducer->multiply(g[j-1], g[0]); + + const u32bit exp_nibbles = (exp.bits() + window_bits - 1) / window_bits; + + BigInt x = reducer->convert_in(1); + for(u32bit j = exp_nibbles; j > 0; j--) + { + for(u32bit k = 0; k != window_bits; k++) + x = reducer->square(x); + u32bit nibble = exp.get_nibble(j-1, window_bits); + if(nibble) + x = reducer->multiply(x, g[nibble-1]); + } + return reducer->convert_out(x); + } + +} + +/************************************************* +* Modular Exponentiation * +*************************************************/ +BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) + { + ModularReducer* reducer = get_reducer(mod); + BigInt x = power_mod(base, exp, reducer); + delete reducer; + return x; + } + +/************************************************* +* Modular Exponentiation Algorithm Dispatch * +*************************************************/ +BigInt power_mod(const BigInt& base, const BigInt& exp, + ModularReducer* reducer) + { + if(base.is_negative()) + throw Invalid_Argument("power_mod: base must be positive"); + if(exp.is_negative()) + throw Invalid_Argument("power_mod: exponent must be positive"); + if(exp.is_zero()) + return 1; + + const u32bit window_bits = window_size(exp.bits()); + + if(base == 2 && !reducer->must_convert()) + return power_mod_g2(exp, reducer); + if(window_bits > 1) + return power_mod_window(base, exp, reducer, window_bits); + return power_mod_l2r(base, exp, reducer); + } + +} --- botan/prf_ssl3.cpp +++ botan/prf_ssl3.cpp @@ -0,0 +1,71 @@ +/************************************************* +* SSL3 PRF Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Return the next inner hash * +*************************************************/ +OctetString next_hash(u32bit where, u32bit want, + HashFunction* md5, HashFunction* sha1, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) + { + if(want > md5->OUTPUT_LENGTH) + throw Internal_Error("SSL3_PRF:next_hash: want is too big"); + + const byte ASCII_A_CHAR = 0x41; + + for(u32bit j = 0; j != where + 1; j++) + sha1->update(ASCII_A_CHAR + where); + sha1->update(secret, secret_len); + sha1->update(seed, seed_len); + SecureVector sha1_hash = sha1->final(); + + md5->update(secret, secret_len); + md5->update(sha1_hash); + SecureVector md5_hash = md5->final(); + + return OctetString(md5_hash, want); + } + +} + +/************************************************* +* SSL3 PRF * +*************************************************/ +SecureVector SSL3_PRF::derive(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) const + { + if(key_len > 416) + throw Exception("SSL3_PRF: Requested key length is too large"); + + std::auto_ptr md5(get_hash("MD5")); + std::auto_ptr sha1(get_hash("SHA-1")); + + OctetString output; + + int counter = 0; + while(key_len) + { + const u32bit produce = std::min(key_len, md5->OUTPUT_LENGTH); + + output = output + next_hash(counter++, produce, md5.get(), sha1.get(), + secret, secret_len, seed, seed_len); + + key_len -= produce; + } + + return output.bits_of(); + } + +} --- botan/prf_tls.cpp +++ botan/prf_tls.cpp @@ -0,0 +1,62 @@ +/************************************************* +* TLS PRF Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* TLS PRF * +*************************************************/ +SecureVector TLS_PRF::derive(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) const + { + u32bit S1_len = (secret_len + 1) / 2, + S2_len = (secret_len + 1) / 2; + const byte* S1 = secret; + const byte* S2 = secret + (secret_len - S2_len); + + SecureVector key1, key2; + key1 = P_hash("MD5", key_len, S1, S1_len, seed, seed_len); + key2 = P_hash("SHA-1", key_len, S2, S2_len, seed, seed_len); + + xor_buf(key1.begin(), key2.begin(), key2.size()); + + return key1; + } + +/************************************************* +* TLS PRF P_hash function * +*************************************************/ +SecureVector TLS_PRF::P_hash(const std::string& hash, u32bit len, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) const + { + SecureVector out; + + HMAC hmac(hash); + hmac.set_key(secret, secret_len); + + SecureVector A(seed, seed_len); + while(len) + { + const u32bit this_block_len = std::min(hmac.OUTPUT_LENGTH, len); + + A = hmac.process(A); + + hmac.update(A); + hmac.update(seed, seed_len); + SecureVector block = hmac.final(); + + out.append(block, this_block_len); + len -= this_block_len; + } + return out; + } + +} --- botan/prf_x942.cpp +++ botan/prf_x942.cpp @@ -0,0 +1,88 @@ +/************************************************* +* X9.42 PRF Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Encode an integer as an OCTET STRING * +*************************************************/ +MemoryVector encode_x942_int(u32bit n) + { + byte n_buf[4]; + for(u32bit j = 0; j != 4; j++) + n_buf[j] = get_byte(j, n); + + DER_Encoder encoder; + DER::encode(encoder, n_buf, 4, OCTET_STRING); + return encoder.get_contents(); + } + +} + +/************************************************* +* X9.42 PRF * +*************************************************/ +SecureVector X942_PRF::derive(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte salt[], u32bit salt_len) const + { + std::auto_ptr hash(get_hash("SHA-1")); + const OID kek_algo(key_wrap_oid); + + SecureVector key; + u32bit counter = 1; + + while(key.size() != key_len) + { + DER_Encoder encoder; + encoder.start_sequence(); + encoder.start_sequence(); + DER::encode(encoder, kek_algo); + encoder.add_raw_octets(encode_x942_int(counter)); + encoder.end_sequence(); + + if(salt_len) + { + encoder.start_explicit(ASN1_Tag(0)); + DER::encode(encoder, salt, salt_len, OCTET_STRING); + encoder.end_explicit(ASN1_Tag(0)); + } + + encoder.start_explicit(ASN1_Tag(2)); + encoder.add_raw_octets(encode_x942_int(8 * key_len)); + encoder.end_explicit(ASN1_Tag(2)); + encoder.end_sequence(); + + hash->update(secret, secret_len); + hash->update(encoder.get_contents()); + SecureVector digest = hash->final(); + key.append(digest, std::min(digest.size(), key_len - key.size())); + + 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; + } + +} --- botan/primes.cpp +++ botan/primes.cpp @@ -0,0 +1,673 @@ +/************************************************* +* Small Primes Table * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#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 }; + +const u64bit PRIME_PRODUCTS[PRIME_PRODUCTS_TABLE_SIZE] = { +0xE221F97C30E94E1DULL, 0xE5B65ED6608B952DULL, 0xF4521CE5D3CA44EFULL, 0xF3EF021E44A7EEC3ULL, +0xF330D66E4349E591ULL, 0x6F6B8463BEE90825ULL, 0xD41D1350609EC855ULL, 0x28681D7AA3190143ULL, +0x2FA51D379842A4AFULL, 0x84AE694AFD8B0547ULL, 0xC7AC609EF16A407BULL, 0xCA376556426DE0FDULL, +0x466324A8372A45D5ULL, 0xAD7D2FB14BF7DC0BULL, 0x7BCD9BF6C6C26323ULL, 0x74709A2A2637FA55ULL, +0x1D640B8FE0CA4311ULL, 0xC93804EEC683CB2DULL, 0xB10594307EA0B7ADULL, 0xDE0244E8F6D2DC17ULL, +0x61DE0343443ED4C5ULL, 0xCF8D577CE72384BBULL, 0x217168EC6F4A928BULL, 0xF5446BCD87F96E6BULL, +0xF7E12D023D06E73DULL, 0x457CBC7E43B62C3FULL, 0x5AE2F68DB28800BFULL, 0x7500EDA80A9C8EA7ULL, +0x8DBC07E86DC4A37FULL, 0x9E40BF0300CA232DULL, 0xC0A9D8342259FCD1ULL, 0xDFE8B5D19367A1C5ULL, +0xFBC11439E02B209DULL, 0xDA0AC1EC9E251F43ULL, 0xAB4E5F28D129622FULL, 0xEBF5FBCBF5587CBDULL, +0xE26B31744B05DC9DULL, 0xE1580FBB4592700BULL, 0x6539F95C9D74F439ULL, 0xB185EF6E9070A559ULL, +0x699ECA919029B14BULL, 0xEBBFC2CC1B0DEE0FULL, 0x8E19279CEAF709FBULL, 0xFA3F354C954330EFULL, +0xAE9362C721216DEFULL, 0xF44253878D02F03DULL, 0xC2D98B01DFE4F3A9ULL, 0xE4A3E0F9407ED71FULL, +0xAE2E9D8F67A52865ULL, 0xF7DEE3EE2D340885ULL, 0xCC1D2DEA66C3C841ULL, 0xA827E8CE4BF5EB07ULL, +0xDF26E6009081BE79ULL, 0x1969811A2B7A6A93ULL, 0x88D31B077DEEB8A3ULL, 0xA15E37A8F401B5C1ULL, +0xB27BF45E6508617BULL, 0xE23D5CA287D9A531ULL, 0xD33CEF8D08A70D3FULL, 0xF26E164CB7B477D5ULL, +0xF070DAE24D8CEDA9ULL, 0x4F580C6048999F4DULL, 0xFBC528EEE00D6CFBULL, 0xE47E34CA3E3EAC63ULL, +0xE2421086C3D09FE5ULL, 0xC35091E86806D213ULL, 0x1F29F3BD0BE9FAB3ULL, 0xFA21995FB84F5A83ULL, +0xBBF6D8395F7047C7ULL, 0xBC28039A69726205ULL, 0xF0324199A11B5D45ULL, 0x969FA74E537EBE09ULL, +0xA474F6C127403A9DULL, 0xEBB6153629ECDEA7ULL, 0xC96E2D7B65D2277BULL, 0xD2B89C851CD9291FULL, +0xEABE76C706F0C3E5ULL, 0xB997188EA5B710D3ULL, 0xB5B20274A0DABB6FULL, 0x89D99F7F39AB2B9BULL, +0x138C3AC887043CCDULL, 0xC6D3E2761D16233FULL, 0x507C4D00D6B6027FULL, 0xBF363571906180F3ULL, +0x89FEA18355BD571DULL, 0xF55905D2F8949905ULL, 0x65F170475F041C6FULL, 0x94C6E638460936A1ULL, +0x809F449762D125EFULL, 0xAC4BC4C3547A71E1ULL, 0xF9315948183BDBC5ULL, 0xC383E883DEA0349BULL, +0xBC33CFE86CA38435ULL, 0xC413C74E3F6F847BULL, 0xE25488813C3CE121ULL, 0xFD33CDA8A0333BEFULL, +0xEDCCA470B26DA57FULL, 0x383533808BD74477ULL, 0x3AC02A15FC89C54DULL, 0x3E12CC83606624F3ULL, +0xAB899B62C0938D01ULL, 0x429DC254C5490571ULL, 0xF5554C6D540DB6A9ULL, 0xFE3F5CCCBAFFDC95ULL, +0xF20E8ABC0340C14FULL, 0xBD633919AA5AB02FULL, 0x532A1FA4D0775045ULL, 0x9F3F943B5D1E6679ULL, +0xA14E33555E99605DULL, 0xC48A6E1EC3CF4793ULL, 0xD00AC683F6B64DB9ULL, 0xB7316C602F3F2DDBULL, +0xABF8EF8B5CABB03DULL, 0xFFCAA72EE6539255ULL, 0xC1CB903C8D764FB7ULL, 0x80300B3B06A6F3F3ULL, +0xC7471C73A380A4AFULL, 0x892E6D86008F82E3ULL, 0x8D040C52D7C6AB79ULL, 0xD35DE032B89A6907ULL, +0xD1CD5A93959C1185ULL, 0xB87C36644FB9B3B7ULL, 0xA827E6B6DE68593FULL, 0xAC16DC9E966EA68FULL, +0xB3E87100AC54DE6DULL, 0xB98014BDAE7021B1ULL, 0xBE350E0F484524D1ULL, 0xC6172BCEA3A11C9BULL, +0xCC01BFD8F5EE2EC3ULL, 0xD1B284C91EED248BULL, 0xFDFF2DE1B95F5687ULL, 0xE21A13779E0CCDC7ULL, +0xE68E732A2ABED62FULL, 0xEC8F38C8B28E0493ULL, 0xF52BDF080F7ABA6FULL, 0xFF40ECA3CCA22CE5ULL, +0x215D0693AD933EB1ULL, 0xBE2B9B2F8ECD578DULL, 0x843F6BF5D2BBF979ULL, 0xCACD47144DAADA59ULL, +0xF19D26474F170045ULL, 0x7A6BA19CE2FBBCD9ULL, 0x525620BB14320123ULL, 0xEBABCCACEACE2A81ULL, +0xDAD688DAC863D2F3ULL, 0x70CF888F6F02D4BBULL, 0xD3EBE9A16C01996FULL, 0xED449526CBEBE513ULL, +0x991DD50C7F17A1B7ULL, 0xD1F37E54FC6589EFULL, 0xB1B72FDE0EA34AFFULL, 0xBF1D75BDDED44FD1ULL, +0xD101DC5EAA25201BULL, 0xDF60F18616AD8EFBULL, 0xED74888F36648FBBULL, 0xFD5051BD895D6539ULL, +0xCCEBE44FA3E6B1BDULL, 0xD52A16F9E33265CBULL, 0xEDD3384401AD1267ULL, 0xF3CC98549791076FULL, +0x6EF7899720A0A93BULL, 0x7DB9EF3F5256F38FULL, 0x9273910ABDE6E503ULL, 0xA3B446CA98554091ULL, +0xB13C2BDE8958E05DULL, 0xBEFA82CB25F97AF1ULL, 0xCDC1FE0211DF150FULL, 0xE32387464B225385ULL, +0xF154C4C2CA8EABF9ULL, 0xCF4E11D8E56F6957ULL, 0xF7BBB96118B42F15ULL, 0x535138221347C85DULL, +0x4FFC85B96C562A71ULL, 0x6C6FD444704EE9A9ULL, 0x81319E967E1AABB3ULL, 0x948BE6486434303BULL, +0xAADD17A4C60E2449ULL, 0xD619D14A9A0B5FBDULL, 0xE2FB3F507D8C64B5ULL, 0xFCFCE80D5BB997DFULL, +0xB08106E9D93A99ADULL, 0x238E12AE75BF1861ULL, 0xE0F83D2ED5DC8AC3ULL, 0x681FF3CFE90D481BULL, +0x805517DDD3E296E7ULL, 0x9BDBC365E2E9E57FULL, 0xBAE52C39C9082107ULL, 0xF09928EC4A4C1503ULL, +0xF26340D17F990C75ULL, 0x97299F4F32B7DB6BULL, 0xC6E38417C7E30011ULL, 0xF582B6E0E6B7830FULL, +0xD0D046F74D1ED633ULL, 0xBEE06A041F778E5DULL, 0xDBE53BF49C3CF227ULL, 0xF9F4E4C91D1537F1ULL, +0xA838BFF645C41F0FULL, 0x458809A605C2264BULL, 0x62C07D00B5C7B939ULL, 0x8F303208051AF4EFULL, +0xCE366281B21E7AFDULL, 0xE750611EA0BE8B55ULL, 0xAACF9921F54349DDULL, 0xB9499C919BEDEB2DULL, +0x8B5E2D6A7C0FED8DULL, 0xB31C12531D85C86BULL, 0xE2F81DD567C198EDULL, 0xFCBF50872C7A85B7ULL, +0xA7C97479B562C749ULL, 0xDBBB14BBF9B4AC85ULL, 0xC69D26F25DEA581DULL, 0xFA3CC64F8D79398DULL, +0x8703AEE0630C7FEFULL, 0xB272C207BD08D637ULL, 0xC50A96A2C6C59C23ULL, 0xFB6694D346303AB1ULL, +0x93F2BA15512C7BE9ULL, 0x7ED5EB28F50A553FULL, 0xB9BB9C7AA9343BD3ULL, 0xE711EA83362E3FEBULL, +0xC417BB9B3F863C89ULL, 0x96A88B47EE3AAB49ULL, 0xDF3ED601F5DCCE23ULL, 0xB211874BB8720877ULL, +0x6F3E9B69CB1BDCDBULL, 0x9B295CC8FEBC20D5ULL, 0xE56F23F76A71387FULL, 0xEA78F5BB0CD1565FULL, +0xA4A428E418FD2B17ULL, 0xDEEF3C10065A26E1ULL, 0x2D1E8F5735933B8DULL, 0xF362A62EB7E3B551ULL, +0xF62327AE7D4E70A5ULL, 0x28B86F69D6FCA5B5ULL, 0x87C63FAA3E25406BULL, 0xD659246185DA101DULL, +0xC10B2CF6559274B7ULL, 0x727BF31FFF9B208BULL, 0xEA55235C4B98064DULL, 0xFBCD0B3F56EABA75ULL, +0xFB0D12857E554175ULL, 0xECC6FD2C8F45CC2FULL, 0xFAE200BB2687381BULL, 0x7C0001DFD91FDB5BULL, +0xDEE61AC82000895BULL, 0x9536C4399D4F3FB7ULL, 0xA8F1E698E4A3297FULL, 0xFA61F6759A6CEE8FULL, +0xCBAE83BF32730B03ULL, 0xDC7C6D1FB9E1633BULL, 0xF12CAF2A95AA8807ULL, 0xDF9CC7A9C8FFEF4DULL, +0xD0744F8438C2E907ULL, 0xB0DA65AB5BB20619ULL, 0x1C0C79A379CFBF8DULL, 0x93AC2BC1F9EC0E29ULL }; + +} --- botan/pubkey.cpp +++ botan/pubkey.cpp @@ -0,0 +1,383 @@ +/************************************************* +* Public Key Base Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Encrypt a message * +*************************************************/ +SecureVector PK_Encryptor::encrypt(const byte in[], u32bit len) const + { + return enc(in, len); + } + +/************************************************* +* Encrypt a message * +*************************************************/ +SecureVector PK_Encryptor::encrypt(const MemoryRegion& in) const + { + return enc(in.begin(), in.size()); + } + +/************************************************* +* Decrypt a message * +*************************************************/ +SecureVector PK_Decryptor::decrypt(const byte in[], u32bit len) const + { + return dec(in, len); + } + +/************************************************* +* Decrypt a message * +*************************************************/ +SecureVector PK_Decryptor::decrypt(const MemoryRegion& in) const + { + return dec(in.begin(), in.size()); + } + +/************************************************* +* PK_Encryptor_MR_with_EME Constructor * +*************************************************/ +PK_Encryptor_MR_with_EME::PK_Encryptor_MR_with_EME(const PK_Encrypting_Key& k, + const std::string& eme) : + key(k), encoder((eme == "Raw") ? 0 : get_eme(eme)) + { + } + +/************************************************* +* Encrypt a message * +*************************************************/ +SecureVector PK_Encryptor_MR_with_EME::enc(const byte msg[], + u32bit length) const + { + SecureVector message; + if(encoder) message = encoder->encode(msg, length, key.max_input_bits()); + else message.set(msg, length); + + if(8*(message.size() - 1) + high_bit(message[0]) > key.max_input_bits()) + throw Exception("PK_Encryptor_MR_with_EME: Input is too large"); + + return key.encrypt(message, message.size()); + } + +/************************************************* +* Return the max size, in bytes, of a message * +*************************************************/ +u32bit PK_Encryptor_MR_with_EME::maximum_input_size() const + { + if(!encoder) + return (key.max_input_bits() / 8); + else + return encoder->maximum_input_size(key.max_input_bits()); + } + +/************************************************* +* PK_Decryptor_MR_with_EME Constructor * +*************************************************/ +PK_Decryptor_MR_with_EME::PK_Decryptor_MR_with_EME(const PK_Decrypting_Key& k, + const std::string& eme) : + key(k), encoder((eme == "Raw") ? 0 : get_eme(eme)) + { + } + +/************************************************* +* Decrypt a message * +*************************************************/ +SecureVector PK_Decryptor_MR_with_EME::dec(const byte msg[], + u32bit length) const + { + try { + SecureVector decrypted = key.decrypt(msg, length); + if(encoder) + return encoder->decode(decrypted, key.max_input_bits()); + else + return decrypted; + } + catch(Invalid_Argument) + { + throw Exception("PK_Decryptor_MR_with_EME: Input is invalid"); + } + catch(Decoding_Error) + { + throw Exception("PK_Decryptor_MR_with_EME: Input is invalid"); + } + } + +/************************************************* +* PK_Signer Constructor * +*************************************************/ +PK_Signer::PK_Signer(const PK_Signing_Key& k, const std::string& emsa_name) : + key(k), emsa(get_emsa(emsa_name)) + { + sig_format = IEEE_1363; + } + +/************************************************* +* Set the signature format * +*************************************************/ +void PK_Signer::set_output_format(Signature_Format format) + { + if(key.message_parts() == 1 && format != IEEE_1363) + throw Invalid_State("PK_Signer: Cannot set the output format for " + + key.algo_name() + " keys"); + sig_format = format; + } + +/************************************************* +* Sign a message * +*************************************************/ +SecureVector PK_Signer::sign_message(const byte msg[], u32bit length) + { + update(msg, length); + return signature(); + } + +/************************************************* +* Sign a message * +*************************************************/ +SecureVector PK_Signer::sign_message(const MemoryRegion& msg) + { + return sign_message(msg, msg.size()); + } + +/************************************************* +* Add more to the message to be signed * +*************************************************/ +void PK_Signer::update(const byte in[], u32bit length) + { + emsa->update(in, length); + } + +/************************************************* +* Add more to the message to be signed * +*************************************************/ +void PK_Signer::update(const MemoryRegion& in) + { + update(in, in.size()); + } + +/************************************************* +* Create a signature * +*************************************************/ +SecureVector PK_Signer::signature() + { + SecureVector encoded = emsa->encoding_of(emsa->raw_data(), + key.max_input_bits()); + SecureVector plain_sig = key.sign(encoded, encoded.size()); + + if(key.message_parts() == 1 || sig_format == IEEE_1363) + return plain_sig; + + if(sig_format == DER_SEQUENCE) + { + if(plain_sig.size() % key.message_parts()) + throw Encoding_Error("PK_Signer: strange signature size found"); + const u32bit SIZE_OF_PART = plain_sig.size() / key.message_parts(); + + std::vector sig_parts(key.message_parts()); + for(u32bit j = 0; j != sig_parts.size(); j++) + sig_parts[j].binary_decode(plain_sig + SIZE_OF_PART*j, SIZE_OF_PART); + + DER_Encoder der_sig; + der_sig.start_sequence(); + for(u32bit j = 0; j != sig_parts.size(); j++) + DER::encode(der_sig, sig_parts[j]); + der_sig.end_sequence(); + + return der_sig.get_contents(); + } + else + throw Encoding_Error("PK_Signer: Unknown signature format " + + to_string(sig_format)); + } + +/************************************************* +* PK_Verifier Constructor * +*************************************************/ +PK_Verifier::PK_Verifier(const PK_Key& k, const std::string& emsa_name) : + emsa(get_emsa(emsa_name)), key(k) + { + sig_format = IEEE_1363; + } + +/************************************************* +* Set the signature format * +*************************************************/ +void PK_Verifier::set_input_format(Signature_Format format) + { + if(key.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 MemoryRegion& msg, + const MemoryRegion& sig) + { + return verify_message(msg, msg.size(), sig, sig.size()); + } + +/************************************************* +* Verify a message * +*************************************************/ +bool PK_Verifier::verify_message(const byte msg[], u32bit msg_length, + const byte sig[], u32bit sig_length) + { + update(msg, msg_length); + return check_signature(sig, sig_length); + } + +/************************************************* +* Append to the message * +*************************************************/ +void PK_Verifier::update(const byte in[], u32bit length) + { + emsa->update(in, length); + } + +/************************************************* +* Append to the message * +*************************************************/ +void PK_Verifier::update(const MemoryRegion& in) + { + emsa->update(in, in.size()); + } + +/************************************************* +* Check a signature * +*************************************************/ +bool PK_Verifier::valid_signature(const byte sig[], u32bit length) + { + return check_signature(sig, length); + } + +/************************************************* +* Check a signature * +*************************************************/ +bool PK_Verifier::check_signature(const MemoryRegion& sig) + { + return check_signature(sig, sig.size()); + } + +/************************************************* +* Check a signature * +*************************************************/ +bool PK_Verifier::check_signature(const byte sig[], u32bit 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 = BER::get_subsequence(decoder); + + u32bit count = 0; + SecureVector real_sig; + while(ber_sig.more_items()) + { + BigInt sig_part; + BER::decode(ber_sig, sig_part); + real_sig.append(BigInt::encode_1363(sig_part, + key.message_part_size())); + count++; + } + if(count != key.message_parts()) + throw Decoding_Error("PK_Verifier: signature size invalid"); + + return validate_signature(emsa->raw_data(), + real_sig, real_sig.size()); + } + else + throw Decoding_Error("PK_Verifier: Unknown signature format " + + to_string(sig_format)); + } + catch(Invalid_Argument) { return false; } + catch(Decoding_Error) { return false; } + } + +/************************************************* +* PK_Verifier_with_MR Constructor * +*************************************************/ +PK_Verifier_with_MR::PK_Verifier_with_MR(const PK_Verifying_with_MR_Key& k, + const std::string& emsa_name) : + PK_Verifier(k, emsa_name), key(k) + { + } + +/************************************************* +* Verify a signature * +*************************************************/ +bool PK_Verifier_with_MR::validate_signature(const MemoryRegion& msg, + const byte sig[], u32bit sig_len) + { + SecureVector output_of_key = key.verify(sig, sig_len); + return emsa->verify(output_of_key, msg, key.max_input_bits()); + } + +/************************************************* +* PK_Verifier_wo_MR Constructor * +*************************************************/ +PK_Verifier_wo_MR::PK_Verifier_wo_MR(const PK_Verifying_wo_MR_Key& k, + const std::string& emsa_name) : + PK_Verifier(k, emsa_name), key(k) + { + } + +/************************************************* +* Verify a signature * +*************************************************/ +bool PK_Verifier_wo_MR::validate_signature(const MemoryRegion& msg, + const byte sig[], u32bit sig_len) + { + SecureVector encoded = emsa->encoding_of(msg, key.max_input_bits()); + return key.verify(encoded, encoded.size(), sig, sig_len); + } + +/************************************************* +* PK_Key_Agreement Constructor * +*************************************************/ +PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& k, + const std::string& k_name) : + key(k), kdf_name(k_name) + { + } + +/************************************************* +* Perform Key Agreement Operation * +*************************************************/ +SymmetricKey PK_Key_Agreement::derive_key(u32bit key_len, + const byte in[], u32bit in_len, + const std::string& params) const + { + return derive_key(key_len, in, in_len, + (const byte*)params.c_str(), params.length()); + } + +/************************************************* +* Perform Key Agreement Operation * +*************************************************/ +SymmetricKey PK_Key_Agreement::derive_key(u32bit key_len, const byte in[], + u32bit in_len, const byte params[], + u32bit params_len) const + { + std::auto_ptr kdf((kdf_name == "Raw") ? 0 : get_kdf(kdf_name)); + OctetString z = key.derive_key(in, in_len); + + if(kdf.get()) + z = kdf->derive_key(key_len, z.bits_of(), params, params_len); + + return z; + } + +} --- botan/pubkey.h +++ botan/pubkey.h @@ -0,0 +1,168 @@ +/************************************************* +* Public Key Interface Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_PUBKEY_H__ +#define BOTAN_PUBKEY_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Public Key Encryptor * +*************************************************/ +class PK_Encryptor + { + public: + SecureVector encrypt(const byte[], u32bit) const; + SecureVector encrypt(const MemoryRegion&) const; + virtual u32bit maximum_input_size() const = 0; + virtual ~PK_Encryptor() {} + private: + virtual SecureVector enc(const byte[], u32bit) const = 0; + }; + +/************************************************* +* Public Key Decryptor * +*************************************************/ +class PK_Decryptor + { + public: + SecureVector decrypt(const byte[], u32bit) const; + SecureVector decrypt(const MemoryRegion&) const; + virtual ~PK_Decryptor() {} + private: + virtual SecureVector dec(const byte[], u32bit) const = 0; + }; + +/************************************************* +* Public Key Signer * +*************************************************/ +class PK_Signer + { + public: + SecureVector sign_message(const byte[], u32bit); + SecureVector sign_message(const MemoryRegion&); + void update(const byte[], u32bit); + void update(const MemoryRegion&); + SecureVector signature(); + + void set_output_format(Signature_Format); + + PK_Signer(const PK_Signing_Key&, const std::string&); + ~PK_Signer() { delete emsa; } + private: + const PK_Signing_Key& key; + Signature_Format sig_format; + EMSA* emsa; + }; + +/************************************************* +* Public Key Verifier * +*************************************************/ +class PK_Verifier + { + public: + bool verify_message(const byte[], u32bit, const byte[], u32bit); + bool verify_message(const MemoryRegion&, + const MemoryRegion&); + + void update(const byte[], u32bit); + void update(const MemoryRegion&); + + bool check_signature(const byte[], u32bit); + bool check_signature(const MemoryRegion&); + + // DEPRECATED FUNCTION + bool valid_signature(const byte[], u32bit); + + void set_input_format(Signature_Format); + + PK_Verifier(const PK_Key&, const std::string&); + virtual ~PK_Verifier() { delete emsa; } + protected: + virtual bool validate_signature(const MemoryRegion&, + const byte[], u32bit) = 0; + Signature_Format sig_format; + EMSA* emsa; + private: + const PK_Key& key; + }; + +/************************************************* +* Key Agreement * +*************************************************/ +class PK_Key_Agreement + { + public: + SymmetricKey derive_key(u32bit, const byte[], u32bit, + const std::string& = "") const; + SymmetricKey derive_key(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + + PK_Key_Agreement(const PK_Key_Agreement_Key&, const std::string&); + private: + const PK_Key_Agreement_Key& key; + const std::string kdf_name; + }; + +/************************************************* +* Encryption with an MR algorithm and an EME * +*************************************************/ +class PK_Encryptor_MR_with_EME : public PK_Encryptor + { + public: + u32bit maximum_input_size() const; + PK_Encryptor_MR_with_EME(const PK_Encrypting_Key&, const std::string&); + ~PK_Encryptor_MR_with_EME() { delete encoder; } + private: + SecureVector enc(const byte[], u32bit) const; + const PK_Encrypting_Key& key; + const EME* encoder; + }; + +/************************************************* +* Decryption with an MR algorithm and an EME * +*************************************************/ +class PK_Decryptor_MR_with_EME : public PK_Decryptor + { + public: + PK_Decryptor_MR_with_EME(const PK_Decrypting_Key&, const std::string&); + ~PK_Decryptor_MR_with_EME() { delete encoder; } + private: + SecureVector dec(const byte[], u32bit) const; + const PK_Decrypting_Key& key; + const EME* encoder; + }; + +/************************************************* +* Public Key Verifier with Message Recovery * +*************************************************/ +class PK_Verifier_with_MR : public PK_Verifier + { + public: + PK_Verifier_with_MR(const PK_Verifying_with_MR_Key&, const std::string&); + private: + bool validate_signature(const MemoryRegion&, const byte[], u32bit); + const PK_Verifying_with_MR_Key& key; + }; + +/************************************************* +* Public Key Verifier without Message Recovery * +*************************************************/ +class PK_Verifier_wo_MR : public PK_Verifier + { + public: + PK_Verifier_wo_MR(const PK_Verifying_wo_MR_Key&, const std::string&); + private: + bool validate_signature(const MemoryRegion&, const byte[], u32bit); + const PK_Verifying_wo_MR_Key& key; + }; + +} + +#endif --- botan/randpool.cpp +++ botan/randpool.cpp @@ -0,0 +1,155 @@ +/************************************************* +* Randpool Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Generate a buffer of random bytes * +*************************************************/ +void Randpool::randomize(byte out[], u32bit length) throw(PRNG_Unseeded) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + generate(system_clock()); + while(length >= output.size()) + { + xor_buf(out, output, output.size()); + length -= output.size(); + out += output.size(); + generate(system_clock()); + } + xor_buf(out, output, length); + } + +/************************************************* +* Refill the output buffer * +*************************************************/ +void Randpool::generate(u64bit input) throw() + { + for(u32bit j = 0; j != 4; j++) + hash->update(get_byte(j, counter)); + for(u32bit j = 0; j != 8; j++) + hash->update(get_byte(j, input)); + hash->update(pool); + + SecureVector poolhash = hash->final(); + + for(u32bit j = 0; j != poolhash.size(); j++) + output[j % output.size()] ^= poolhash[j]; + cipher->encrypt(output); + + if(counter % ITERATIONS_BEFORE_RESEED == 0) + mix_pool(); + counter++; + } + +/************************************************* +* Mix the randomness pool * +*************************************************/ +void Randpool::mix_pool() throw() + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + + cipher->set_key(output, output.size()); + + xor_buf(pool, pool + BLOCK_SIZE*(POOL_BLOCKS-1), BLOCK_SIZE); + cipher->encrypt(pool); + for(u32bit j = 1; j != POOL_BLOCKS; j++) + { + const byte* previous_block = pool + BLOCK_SIZE*(j-1); + byte* this_block = pool + BLOCK_SIZE*j; + xor_buf(this_block, previous_block, BLOCK_SIZE); + cipher->encrypt(this_block); + } + + for(u32bit j = 0; j != output.size(); j++) + output[j] ^= 0xFF; + cipher->encrypt(output); + } + +/************************************************* +* Add entropy to the internal state * +*************************************************/ +void Randpool::add_randomness(const byte data[], u32bit length) throw() + { + update_entropy(data, length, pool.size()); + + while(length) + { + u32bit added = std::min(pool.size() / 2, length); + xor_buf(pool, data, added); + generate(system_clock()); + mix_pool(); + length -= added; + data += added; + } + generate(system_clock()); + mix_pool(); + } + +/************************************************* +* Check if the the pool is seeded * +*************************************************/ +bool Randpool::is_seeded() const + { + return (entropy >= 256); + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void Randpool::clear() throw() + { + cipher->clear(); + hash->clear(); + pool.clear(); + output.clear(); + entropy = counter = 0; + } + +/************************************************* +* Return the name of this type * +*************************************************/ +std::string Randpool::name() const + { + return "Randpool"; + } + +/************************************************* +* Randpool Constructor * +*************************************************/ +Randpool::Randpool() : ITERATIONS_BEFORE_RESEED(8), POOL_BLOCKS(64) + { + cipher = get_block_cipher("AES-128"); + hash = get_hash("SHA-1"); + + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + output.create(BLOCK_SIZE); + pool.create(POOL_BLOCKS * BLOCK_SIZE); + entropy = counter = 0; + + if(hash->OUTPUT_LENGTH < BLOCK_SIZE || !cipher->valid_keylength(BLOCK_SIZE)) + throw Internal_Error("Randpool: Invalid algorithm combination " + + cipher->name() + "/" + hash->name()); + + cipher->set_key(output, output.size()); + for(u32bit j = 0; j != ITERATIONS_BEFORE_RESEED + 1; j++) + generate(system_clock()); + } + +/************************************************* +* Randpool Destructor * +*************************************************/ +Randpool::~Randpool() + { + delete cipher; + delete hash; + } + +} --- botan/randpool.h +++ botan/randpool.h @@ -0,0 +1,38 @@ +/************************************************* +* Randpool Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_RANDPOOL_H__ +#define BOTAN_RANDPOOL_H__ + +#include + +namespace Botan { + +/************************************************* +* Randpool * +*************************************************/ +class Randpool : public RandomNumberGenerator + { + public: + void randomize(byte[], u32bit) throw(PRNG_Unseeded); + bool is_seeded() const; + void clear() throw(); + std::string name() const; + Randpool(); + ~Randpool(); + private: + void add_randomness(const byte[], u32bit) throw(); + void generate(u64bit) throw(); + void mix_pool() throw(); + const u32bit ITERATIONS_BEFORE_RESEED, POOL_BLOCKS; + BlockCipher* cipher; + HashFunction* hash; + SecureVector pool, output; + u32bit counter; + }; + +} + +#endif --- botan/readme.txt +++ botan/readme.txt @@ -0,0 +1,38 @@ +This version of Botan was modified by Matt Johnston (matt ucc.asn.au) on +November 25 2004 for use with Monotone. + +Changes are the addition of rudimentary gzip (de)compression, and the ability +to decode un-encrypted RAW_BER PKCS8 keys, as well as large amounts of path +rearrangements. + + + +Botan: Version 1.4.3, November 6, 2004 + +Botan is a C++ class library for performing a wide variety of cryptographic +operations, including encryption, hashing, authentication, public key +encryption and signatures, and creating and using X.509v3 certificates and +CRLs. Import/export of PKCS #8 private keys (with optional PKCS #5 v2.0 +encryption), and the creation and processing of PKCS #10 certificate requests +is also supported. Botan includes a large number of algorithms, including: + +* Public Key Algorithms: Diffie-Hellman, DSA, ElGamal, Nyberg-Rueppel, + Rabin-Williams, RSA +* Block Ciphers: AES, Blowfish, CAST-128, CAST-256, DES/DESX/TripleDES, GOST, + IDEA, Lion, Luby-Rackoff, MISTY1, RC2, RC5, RC6, SAFER-SK, Serpent, + Skipjack, Square, TEA, Twofish, XTEA +* Stream Ciphers: ARC4, ISAAC, SEAL, WiderWake4+1 +* Hash Functions: HAS-160, HAVAL, MD2, MD4, MD5, RIPEMD-128, RIPEMD-160, + SHA-160, SHA-256, SHA-384, SHA-512, Tiger, Whirlpool +* MACs: ANSI X9.19 MAC, HMAC, OMAC, SSL3-MAC + +For build instructions, read 'doc/building.pdf'. The license can be found in +'doc/license.txt', and the ChangeLog is in 'doc/log.txt'. + +Check http://botan.randombit.net/ for announcements and news. If you'll be +developing code using Botan, consider joining the mailing lists; links to +subscriptions forms and the archives can be found on the web page. Feel free to +contact me with any questions or comments. + +Regards, + Jack Lloyd (address@hidden) --- botan/reducer.cpp +++ botan/reducer.cpp @@ -0,0 +1,53 @@ +/************************************************* +* Modular Reducer Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Construct a ModularReducer * +*************************************************/ +ModularReducer::ModularReducer(const BigInt& n) : modulus(n) + { + if(modulus <= 0) + throw Invalid_Argument("ModularReducer: modulus must be positive"); + if(modulus.size() > 8 && !power_of_2(modulus.size())) + modulus.grow_reg((1 << high_bit(modulus.size())) - modulus.size()); + } + +/************************************************* +* Convert to the modular form * +*************************************************/ +BigInt ModularReducer::convert_in(const BigInt& i) const + { + return i; + } + +/************************************************* +* Convert from the modular form * +*************************************************/ +BigInt ModularReducer::convert_out(const BigInt& i) const + { + return i; + } + +/************************************************* +* Modular Multiplication * +*************************************************/ +BigInt ModularReducer::multiply(const BigInt& x, const BigInt& y) const + { + return reduce(x * y); + } + +/************************************************* +* Modular Squaring * +*************************************************/ +BigInt ModularReducer::square(const BigInt& x) const + { + return multiply(x, x); + } + +} --- botan/reducer.h +++ botan/reducer.h @@ -0,0 +1,43 @@ +/************************************************* +* Modular Reducer Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_MODARITH_H__ +#define BOTAN_MODARITH_H__ + +#include + +namespace Botan { + +/************************************************* +* Modular Reducer Base Class * +*************************************************/ +class ModularReducer + { + public: + virtual BigInt multiply(const BigInt&, const BigInt&) const; + virtual BigInt square(const BigInt&) const; + virtual BigInt reduce(const BigInt&) const = 0; + + virtual bool must_convert() const { return false; } + + virtual BigInt convert_in(const BigInt&) const; + virtual BigInt convert_out(const BigInt&) const; + + const BigInt& get_modulus() const { return modulus; } + + ModularReducer(const BigInt&); + virtual ~ModularReducer() {} + protected: + const BigInt modulus; + }; + +/************************************************* +* Get a modular reducer * +*************************************************/ +ModularReducer* get_reducer(const BigInt&, bool = false); + +} + +#endif --- botan/rng.cpp +++ botan/rng.cpp @@ -0,0 +1,203 @@ +/************************************************* +* Global RNG Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Global RNG/EntropySource state * +*************************************************/ +RandomNumberGenerator* global_rng = 0; +RandomNumberGenerator* nonce_rng = 0; +std::vector sources; +Mutex* global_rng_lock = 0; +Mutex* sources_lock = 0; + +/************************************************* +* Try to do a poll on an EntropySource * +*************************************************/ +u32bit poll_es(EntropySource* source, bool slow_poll) + { + SecureVector buffer(256); + u32bit got = 0; + + if(slow_poll) got = source->slow_poll(buffer.begin(), buffer.size()); + else got = source->fast_poll(buffer.begin(), buffer.size()); + + Global_RNG::add_entropy(buffer.begin(), got); + return entropy_estimate(buffer.begin(), got); + } + +/************************************************* +* Seed the nonce RNG * +*************************************************/ +void seed_nonce_rng() + { + if(!global_rng->is_seeded()) + return; + + while(!nonce_rng->is_seeded()) + { + SecureVector entropy(64); + global_rng->randomize(entropy.begin(), entropy.size()); + nonce_rng->add_entropy(entropy.begin(), entropy.size()); + } + } + +} + +namespace Global_RNG { + +/************************************************* +* Get entropy from the global RNG * +*************************************************/ +void randomize(byte output[], u32bit size, RNG_Quality level) + { + const std::string LTERM_CIPHER = "WiderWake4+1"; + + if(!global_rng || !nonce_rng) + throw Invalid_State("Global_RNG::randomize: The global RNG is unset"); + + Mutex_Holder lock(global_rng_lock); + + if(level == Nonce) + nonce_rng->randomize(output, size); + else if(level == SessionKey) + global_rng->randomize(output, size); + else if(level == LongTermKey) + { + global_rng->randomize(output, size); + if(have_stream_cipher(LTERM_CIPHER)) + { + std::auto_ptr cipher(get_stream_cipher(LTERM_CIPHER)); + SecureVector key(cipher->MAXIMUM_KEYLENGTH); + global_rng->randomize(key.begin(), key.size()); + cipher->set_key(key.begin(), key.size()); + cipher->encrypt(output, size); + } + } + else + throw Invalid_Argument("Global_RNG::randomize: Invalid RNG_Quality"); + } + +/************************************************* +* Get entropy from the global RNG * +*************************************************/ +byte random(RNG_Quality level) + { + byte ret = 0; + randomize(&ret, 1, level); + return ret; + } + +/************************************************* +* Add entropy to the global RNG * +*************************************************/ +void add_entropy(const byte entropy[], u32bit size) + { + if(!global_rng || !nonce_rng) + throw Invalid_State("Global_RNG::add_entropy: The global RNG is unset"); + + Mutex_Holder lock(global_rng_lock); + global_rng->add_entropy(entropy, size); + seed_nonce_rng(); + } + +/************************************************* +* Add entropy to the global RNG * +*************************************************/ +void add_entropy(EntropySource& src, bool slow_poll) + { + if(!global_rng || !nonce_rng) + throw Invalid_State("Global_RNG::add_entropy: The global RNG is unset"); + + Mutex_Holder lock(global_rng_lock); + global_rng->add_entropy(src, slow_poll); + seed_nonce_rng(); + } + +/************************************************* +* Add an EntropySource to the list * +*************************************************/ +void add_es(EntropySource* src, bool last) + { + Mutex_Holder lock(sources_lock); + if(last) + sources.push_back(src); + else + sources.insert(sources.begin(), src); + } + +/************************************************* +* Seed the global RNG * +*************************************************/ +u32bit seed(bool slow_poll, u32bit bits_to_get) + { + u32bit bits = 0; + for(u32bit j = 0; j != sources.size(); j++) + { + bits += poll_es(sources[j], slow_poll); + if(bits_to_get && bits >= bits_to_get) + return bits; + } + return bits; + } + +} + +namespace Init { + +/************************************************* +* Initialize the RNG system * +*************************************************/ +void init_rng_subsystem() + { + global_rng_lock = get_mutex(); + sources_lock = get_mutex(); + } + +/************************************************* +* Deinitialize the RNG system * +*************************************************/ +void shutdown_rng_subsystem() + { + if(sources_lock && sources.size()) + { + Mutex_Holder lock(sources_lock); + for(u32bit j = 0; j != sources.size(); j++) + delete sources[j]; + sources.clear(); + } + delete sources_lock; + sources_lock = 0; + delete global_rng_lock; + global_rng_lock = 0; + } + +/************************************************* +* Setup the global RNG * +*************************************************/ +void set_global_rngs(RandomNumberGenerator* rng1, RandomNumberGenerator* rng2) + { + if(global_rng) + delete global_rng; + if(nonce_rng) + delete nonce_rng; + + global_rng = rng1; + nonce_rng = rng2; + } + +} + +} --- botan/rng.h +++ botan/rng.h @@ -0,0 +1,43 @@ +/************************************************* +* Global RNG Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_GLOBAL_RNG_H__ +#define BOTAN_GLOBAL_RNG_H__ + +#include + +namespace Botan { + +/************************************************* +* RNG Access and Seeding Functions * +*************************************************/ +namespace Global_RNG { + +void randomize(byte[], u32bit, RNG_Quality = SessionKey); +byte random(RNG_Quality = SessionKey); + +void add_entropy(const byte[], u32bit); +void add_entropy(EntropySource&, bool = true); + +u32bit seed(bool = true, u32bit = 256); + +void add_es(EntropySource*, bool = true); + +} + +/************************************************* +* RNG Control Functions * +*************************************************/ +namespace Init { + +void set_global_rngs(RandomNumberGenerator*, RandomNumberGenerator*); +void init_rng_subsystem(); +void shutdown_rng_subsystem(); + +} + +} + +#endif --- botan/rsa.cpp +++ botan/rsa.cpp @@ -0,0 +1,155 @@ +/************************************************* +* RSA Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* RSA_PublicKey Constructor * +*************************************************/ +RSA_PublicKey::RSA_PublicKey(const BigInt& mod, const BigInt& exp) + { + n = mod; + e = exp; + X509_load_hook(); + } + +/************************************************* +* RSA Public Operation * +*************************************************/ +BigInt RSA_PublicKey::public_op(const BigInt& i) const + { + if(i >= n) + throw Invalid_Argument(algo_name() + "::public_op: input is too large"); + return core.public_op(i); + } + +/************************************************* +* RSA Encryption Function * +*************************************************/ +SecureVector RSA_PublicKey::encrypt(const byte in[], u32bit len) const + { + BigInt i(in, len); + return BigInt::encode_1363(public_op(i), n.bytes()); + } + +/************************************************* +* RSA Verification Function * +*************************************************/ +SecureVector RSA_PublicKey::verify(const byte in[], u32bit len) const + { + BigInt i(in, len); + return BigInt::encode(public_op(i)); + } + +/************************************************* +* Create a RSA private key * +*************************************************/ +RSA_PrivateKey::RSA_PrivateKey(u32bit bits, u32bit exp) + { + if(bits < 512) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + to_string(bits) + " bits long"); + if(exp < 3 || exp % 2 == 0) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + p = random_prime((bits + 1) / 2, LongTermKey, e); + q = random_prime(bits - p.bits(), LongTermKey, e); + d = inverse_mod(e, lcm(p - 1, q - 1)); + + PKCS8_load_hook(); + check_generated_private(); + + if(n.bits() != bits) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +/************************************************* +* RSA_PrivateKey Constructor * +*************************************************/ +RSA_PrivateKey::RSA_PrivateKey(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; + + if(d == 0) + d = inverse_mod(e, lcm(p - 1, q - 1)); + + PKCS8_load_hook(); + check_loaded_private(); + } + +/************************************************* +* RSA Private Operation * +*************************************************/ +BigInt RSA_PrivateKey::private_op(const byte in[], u32bit length) const + { + BigInt i(in, length); + if(i >= n) + throw Invalid_Argument(algo_name() + "::private_op: input is too large"); + + BigInt r = core.private_op(i); + if(i != public_op(r)) + throw Self_Test_Failure(algo_name() + " private operation check failed"); + return r; + } + +/************************************************* +* RSA Decryption Operation * +*************************************************/ +SecureVector RSA_PrivateKey::decrypt(const byte in[], u32bit len) const + { + return BigInt::encode(private_op(in, len)); + } + +/************************************************* +* RSA Signature Operation * +*************************************************/ +SecureVector RSA_PrivateKey::sign(const byte in[], u32bit len) const + { + return BigInt::encode_1363(private_op(in, len), n.bytes()); + } + +/************************************************* +* Check Private RSA Parameters * +*************************************************/ +bool RSA_PrivateKey::check_key(bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(strong)) + return false; + + if(!strong) + return true; + + if((e * d) % lcm(p - 1, q - 1) != 1) + return false; + + try { + KeyPair::check_key(get_pk_encryptor(*this, "EME1(SHA-1)"), + get_pk_decryptor(*this, "EME1(SHA-1)") + ); + + KeyPair::check_key(get_pk_signer(*this, "EMSA4(SHA-1)"), + get_pk_verifier(*this, "EMSA4(SHA-1)") + ); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +} --- botan/rsa.h +++ botan/rsa.h @@ -0,0 +1,56 @@ +/************************************************* +* RSA Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_RSA_H__ +#define BOTAN_RSA_H__ + +#include + +namespace Botan { + +/************************************************* +* RSA Public Key * +*************************************************/ +class RSA_PublicKey : public PK_Encrypting_Key, + public PK_Verifying_with_MR_Key, + public virtual IF_Scheme_PublicKey + { + public: + SecureVector encrypt(const byte[], u32bit) const; + SecureVector verify(const byte[], u32bit) const; + + RSA_PublicKey(const BigInt&, const BigInt&); + protected: + BigInt public_op(const BigInt&) const; + std::string algo_name() const { return "RSA"; } + RSA_PublicKey() {} + private: + friend X509_PublicKey* get_public_key(const std::string&); + }; + +/************************************************* +* RSA Private Key * +*************************************************/ +class RSA_PrivateKey : public RSA_PublicKey, public PK_Decrypting_Key, + public PK_Signing_Key, public IF_Scheme_PrivateKey + { + public: + SecureVector decrypt(const byte[], u32bit) const; + SecureVector sign(const byte[], u32bit) const; + + bool check_key(bool) const; + + RSA_PrivateKey(const BigInt&, const BigInt&, const BigInt&, + const BigInt& = 0, const BigInt& = 0); + RSA_PrivateKey(u32bit, u32bit = 65537); + private: + friend PKCS8_PrivateKey* get_private_key(const std::string&); + BigInt private_op(const byte[], u32bit) const; + RSA_PrivateKey() {} + }; + +} + +#endif --- botan/s2k.cpp +++ botan/s2k.cpp @@ -0,0 +1,53 @@ +/************************************************* +* S2K Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Derive a key from a passphrase * +*************************************************/ +OctetString S2K::derive_key(u32bit key_len, + const std::string& passphrase) const + { + return derive(key_len, passphrase, salt, salt.size(), iterations()); + } + +/************************************************* +* Set the number of iterations * +*************************************************/ +void S2K::set_iterations(u32bit i) + { + iter = i; + } + +/************************************************* +* Change the salt * +*************************************************/ +void S2K::change_salt(const byte new_salt[], u32bit length) + { + salt.set(new_salt, length); + } + +/************************************************* +* Change the salt * +*************************************************/ +void S2K::change_salt(const MemoryRegion& new_salt) + { + change_salt(new_salt.begin(), new_salt.size()); + } + +/************************************************* +* Create a new random salt * +*************************************************/ +void S2K::new_random_salt(u32bit length) + { + salt.create(length); + Global_RNG::randomize(salt, length, Nonce); + } + +} --- botan/s2k.h +++ botan/s2k.h @@ -0,0 +1,42 @@ +/************************************************* +* S2K Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_S2K_H__ +#define BOTAN_S2K_H__ + +#include + +namespace Botan { + +/************************************************* +* S2K Interface * +*************************************************/ +class S2K : public Algorithm + { + public: + virtual S2K* clone() const = 0; + + OctetString derive_key(u32bit, const std::string&) const; + + void set_iterations(u32bit); + void change_salt(const byte[], u32bit); + void change_salt(const MemoryRegion&); + void new_random_salt(u32bit); + + u32bit iterations() const { return iter; } + SecureVector current_salt() const { return salt; } + + S2K() { iter = 0; } + virtual ~S2K() {} + private: + virtual OctetString derive(u32bit, const std::string&, + const byte[], u32bit, u32bit) const = 0; + SecureVector salt; + u32bit iter; + }; + +} + +#endif --- botan/secalloc.h +++ botan/secalloc.h @@ -0,0 +1,30 @@ +/************************************************* +* Memory Allocator Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ALLOCATOR_H__ +#define BOTAN_ALLOCATOR_H__ + +#include + +namespace Botan { + +/************************************************* +* Allocator * +*************************************************/ +class Allocator + { + public: + virtual void* allocate(u32bit) const = 0; + virtual void deallocate(void*, u32bit) const = 0; + + virtual void init() {} + virtual void destroy() {} + + virtual ~Allocator() {} + }; + +} + +#endif --- botan/secmem.h +++ botan/secmem.h @@ -0,0 +1,219 @@ +/************************************************* +* Secure Memory Buffers Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__ +#define BOTAN_SECURE_MEMORY_BUFFERS_H__ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Variable Length Memory Buffer * +*************************************************/ +template +class MemoryRegion + { + public: + u32bit size() const { return used; } + u32bit bits() const { return 8*used; } + u32bit is_empty() const { return (used == 0); } + u32bit has_items() const { return (used != 0); } + + operator T* () { return buf; } + operator const T* () const { return buf; } + + T* begin() { return buf; } + const T* begin() const { return buf; } + + T* end() { return (buf + size()); } + const T* end() const { return (buf + size()); } + + bool operator==(const MemoryRegion& in) const + { + if(size() == in.size() && std::equal(begin(), end(), in.begin())) + return true; + return false; + } + + bool operator<(const MemoryRegion&) const; + + bool operator!=(const MemoryRegion& in) const + { return (!(*this == in)); } + MemoryRegion& operator=(const MemoryRegion& in) + { if(this != &in) set(in); return (*this); } + + void copy(const T in[], u32bit n) + { copy_mem(buf, in, std::min(size(), n)); } + void copy(u32bit off, const T in[], u32bit n) + { copy_mem(buf + off, in, std::min(size() - off, n)); } + + void set(const T in[], u32bit n) { create(n); copy(in, n); } + void set(const MemoryRegion& in) { set(in.begin(), in.size()); } + + void append(const T data[], u32bit n) + { grow_by(n); copy(size() - n, data, n); } + void append(T x) { append(&x, 1); } + void append(const MemoryRegion& x) { append(x.begin(), x.size()); } + + void clear() { clear_mem(buf, allocated); } + void destroy() { create(0); } + + void create(u32bit); + void grow_to(u32bit) const; + void grow_by(u32bit n) const { grow_to(n + size()); } + void swap(MemoryRegion&); + + ~MemoryRegion() { deallocate(buf, allocated); } + protected: + MemoryRegion() { buf = 0; alloc = 0; used = allocated = 0; } + MemoryRegion(const MemoryRegion& copy) + { + buf = 0; + used = allocated = 0; + alloc = copy.alloc; + set(copy.buf, copy.used); + } + + void init(bool lock, u32bit size = 0) + { alloc = get_allocator(lock ? "" : "malloc"); create(size); } + private: + T* allocate(u32bit n) const { return (T*)alloc->allocate(sizeof(T)*n); } + void deallocate(T* p, u32bit n) const + { alloc->deallocate(p, sizeof(T)*n); } + + mutable T* buf; + mutable u32bit used; + mutable u32bit allocated; + const Allocator* alloc; + }; + +/************************************************* +* Create a new buffer * +*************************************************/ +template +void MemoryRegion::create(u32bit n) + { + if(n <= allocated) { clear(); used = n; return; } + deallocate(buf, allocated); + buf = allocate(n); + allocated = used = n; + } + +/************************************************* +* Increase the size of the buffer * +*************************************************/ +template +void MemoryRegion::grow_to(u32bit n) const + { + const u32bit VECTOR_OVER_ALLOCATE = BOTAN_VECTOR_OVER_ALLOCATE; + + if(n <= used) return; + if(n <= allocated) + { + clear_mem(buf + used, n - used); + used = n; + return; + } + T* new_buf = allocate(n + VECTOR_OVER_ALLOCATE); + copy_mem(new_buf, buf, used); + deallocate(buf, allocated); + buf = new_buf; + used = n; + allocated = n + VECTOR_OVER_ALLOCATE; + } + +/************************************************* +* Compare this buffer with another one * +*************************************************/ +template +bool MemoryRegion::operator<(const MemoryRegion& in) const + { + if(size() < in.size()) return true; + if(size() > in.size()) return false; + + for(u32bit j = 0; j != size(); j++) + { + if(buf[j] < in[j]) return true; + if(buf[j] > in[j]) return false; + } + + return false; + } + +/************************************************* +* Swap this buffer with another one * +*************************************************/ +template +void MemoryRegion::swap(MemoryRegion& x) + { + std::swap(buf, x.buf); + std::swap(used, x.used); + std::swap(allocated, x.allocated); + std::swap(alloc, x.alloc); + } + +/************************************************* +* Unlocked Variable Length Buffer * +*************************************************/ +template +class MemoryVector : public MemoryRegion + { + public: + MemoryVector& operator=(const MemoryRegion& in) + { if(this != &in) set(in); return (*this); } + + MemoryVector(u32bit n = 0) { MemoryRegion::init(false, n); } + MemoryVector(const T in[], u32bit n) + { MemoryRegion::init(false); set(in, n); } + MemoryVector(const MemoryRegion& in) + { MemoryRegion::init(false); set(in); } + MemoryVector(const MemoryRegion& in1, const MemoryRegion& in2) + { MemoryRegion::init(false); set(in1); append(in2); } + }; + +/************************************************* +* Locked Variable Length Buffer * +*************************************************/ +template +class SecureVector : public MemoryRegion + { + public: + SecureVector& operator=(const MemoryRegion& in) + { if(this != &in) set(in); return (*this); } + + SecureVector(u32bit n = 0) { MemoryRegion::init(true, n); } + SecureVector(const T in[], u32bit n) + { MemoryRegion::init(true); set(in, n); } + SecureVector(const MemoryRegion& in) + { MemoryRegion::init(true); set(in); } + SecureVector(const MemoryRegion& in1, const MemoryRegion& in2) + { MemoryRegion::init(true); set(in1); append(in2); } + }; + +/************************************************* +* Locked Fixed Length Buffer * +*************************************************/ +template +class SecureBuffer : public MemoryRegion + { + public: + SecureBuffer& operator=(const SecureBuffer& in) + { if(this != &in) set(in); return (*this); } + + SecureBuffer() { MemoryRegion::init(true, L); } + SecureBuffer(const T in[], u32bit n) + { MemoryRegion::init(true, L); copy(in, n); } + private: + SecureBuffer& operator=(const MemoryRegion& in) + { if(this != &in) set(in); return (*this); } + }; + +} + +#endif --- botan/secqueue.cpp +++ botan/secqueue.cpp @@ -0,0 +1,198 @@ +/************************************************* +* SecureQueue Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* SecureQueueNode * +*************************************************/ +class SecureQueueNode + { + public: + u32bit write(const byte input[], u32bit length) + { + u32bit copied = std::min(length, buffer.size() - end); + copy_mem(buffer + end, input, copied); + end += copied; + return copied; + } + u32bit read(byte output[], u32bit length) + { + u32bit copied = std::min(length, end - start); + copy_mem(output, buffer + start, copied); + start += copied; + return copied; + } + u32bit peek(byte output[], u32bit length, u32bit offset = 0) + { + const u32bit left = end - start; + if(offset >= left) return 0; + u32bit copied = std::min(length, left - offset); + copy_mem(output, buffer + start + offset, copied); + return copied; + } + u32bit size() const { return (end - start); } + SecureQueueNode() { next = 0; start = end = 0; } + ~SecureQueueNode() { next = 0; start = end = 0; } + private: + friend class SecureQueue; + SecureQueueNode* next; + SecureBuffer buffer; + u32bit start, end; + }; + +/************************************************* +* Create a SecureQueue * +*************************************************/ +SecureQueue::SecureQueue() : Filter(0) + { + head = tail = new SecureQueueNode; + } + +/************************************************* +* Copy a SecureQueue * +*************************************************/ +SecureQueue::SecureQueue(const SecureQueue& input) : Filter(0), DataSource() + { + 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 = 0; + } + +/************************************************* +* 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[], u32bit length) + { + if(!head) + head = tail = new SecureQueueNode; + while(length) + { + const u32bit n = tail->write(input, length); + input += n; + length -= n; + if(length) + { + tail->next = new SecureQueueNode; + tail = tail->next; + } + } + } + +/************************************************* +* Read some bytes from the queue * +*************************************************/ +u32bit SecureQueue::read(byte output[], u32bit length) + { + u32bit got = 0; + while(length && head) + { + const u32bit n = head->read(output, length); + output += n; + got += n; + length -= n; + if(head->size() == 0) + { + SecureQueueNode* holder = head->next; + delete head; + head = holder; + } + } + return got; + } + +/************************************************* +* Read data, but do not remove it from queue * +*************************************************/ +u32bit SecureQueue::peek(byte output[], u32bit length, u32bit offset) const + { + SecureQueueNode* current = head; + + while(offset && current) + { + if(offset >= current->size()) + { + offset -= current->size(); + current = current->next; + } + else + break; + } + + u32bit got = 0; + while(length && current) + { + const u32bit n = current->peek(output, length, offset); + offset = 0; + output += n; + got += n; + length -= n; + current = current->next; + } + return got; + } + +/************************************************* +* Return how many bytes the queue holds * +*************************************************/ +u32bit SecureQueue::size() const + { + SecureQueueNode* current = head; + u32bit 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); + } + +} --- botan/secqueue.h +++ botan/secqueue.h @@ -0,0 +1,41 @@ +/************************************************* +* SecureQueue Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_SECURE_QUEUE_H__ +#define BOTAN_SECURE_QUEUE_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* SecureQueue * +*************************************************/ +class SecureQueue : public Filter, public DataSource + { + public: + void write(const byte[], u32bit); + + u32bit read(byte[], u32bit); + u32bit peek(byte[], u32bit, u32bit = 0) const; + + bool end_of_data() const; + u32bit size() const; + bool attachable() { return false; } + + SecureQueue& operator=(const SecureQueue&); + SecureQueue(); + SecureQueue(const SecureQueue&); + ~SecureQueue() { destroy(); } + private: + void destroy(); + class SecureQueueNode* head; + class SecureQueueNode* tail; + }; + +} + +#endif --- botan/sha160.cpp +++ botan/sha160.cpp @@ -0,0 +1,122 @@ +/************************************************* +* SHA-160 Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* SHA-160 Compression Function * +*************************************************/ +void SHA_160::hash(const byte input[]) + { + for(u32bit j = 0; j != 16; j++) + W[j] = make_u32bit(input[4*j], input[4*j+1], input[4*j+2], input[4*j+3]); + for(u32bit j = 16; j != 80; j++) + W[j] = rotate_left((W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16]), 1); + + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4]; + + 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]); + + digest[0] += A; digest[1] += B; digest[2] += C; + digest[3] += D; digest[4] += E; + } + +/************************************************* +* Copy out the digest * +*************************************************/ +void SHA_160::copy_out(byte output[]) + { + for(u32bit j = 0; j != OUTPUT_LENGTH; j++) + output[j] = get_byte(j % 4, digest[j/4]); + } + +/************************************************* +* SHA-160 F1 Function * +*************************************************/ +void SHA_160::F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg) + { + E += rotate_left(A, 5) + (D ^ (B & (C ^ D))) + msg + 0x5A827999; + B = rotate_left(B, 30); + } + +/************************************************* +* SHA-160 F2 Function * +*************************************************/ +void SHA_160::F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg) + { + E += rotate_left(A, 5) + (B ^ C ^ D) + msg + 0x6ED9EBA1; + B = rotate_left(B, 30); + } + +/************************************************* +* SHA-160 F3 Function * +*************************************************/ +void SHA_160::F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg) + { + E += rotate_left(A, 5) + ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC; + B = rotate_left(B, 30); + } + +/************************************************* +* SHA-160 F4 Function * +*************************************************/ +void SHA_160::F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg) + { + E += rotate_left(A, 5) + (B ^ C ^ D) + msg + 0xCA62C1D6; + B = rotate_left(B, 30); + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void SHA_160::clear() throw() + { + MDx_HashFunction::clear(); + W.clear(); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} --- botan/sha160.h +++ botan/sha160.h @@ -0,0 +1,40 @@ +/************************************************* +* SHA-160 Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_SHA_160_H__ +#define BOTAN_SHA_160_H__ + +#include + +namespace Botan { + +/************************************************* +* SHA-160 * +*************************************************/ +class SHA_160 : public MDx_HashFunction + { + public: + void clear() throw(); + std::string name() const { return "SHA-160"; } + HashFunction* clone() const { return new SHA_160; } + SHA_160() : MDx_HashFunction(20, 64, true, true) { clear(); } + private: + friend class Gamma; + friend class FIPS_186_RNG; + + void hash(const byte[]); + void copy_out(byte[]); + + static void F1(u32bit, u32bit&, u32bit, u32bit, u32bit&, u32bit); + static void F2(u32bit, u32bit&, u32bit, u32bit, u32bit&, u32bit); + static void F3(u32bit, u32bit&, u32bit, u32bit, u32bit&, u32bit); + static void F4(u32bit, u32bit&, u32bit, u32bit, u32bit&, u32bit); + SecureBuffer W; + SecureBuffer digest; + }; + +} + +#endif --- botan/socket.h +++ botan/socket.h @@ -0,0 +1,31 @@ +/************************************************* +* Socket Interface Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_SOCKET_H__ +#define BOTAN_SOCKET_H__ + +#include + +namespace Botan { + +/************************************************* +* Socket Base Class * +*************************************************/ +class Socket + { + public: + virtual u32bit read(byte[], u32bit) = 0; + virtual void write(const byte[], u32bit) = 0; + + virtual bool can_read() = 0; + + virtual void close() = 0; + + virtual ~Socket() {} + }; + +} + +#endif --- botan/symkey.cpp +++ botan/symkey.cpp @@ -0,0 +1,136 @@ +/************************************************* +* OctetString Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Create an OctetString from RNG output * +*************************************************/ +void OctetString::change(u32bit length, RNG_Quality level) + { + bits.create(length); + Global_RNG::randomize(bits, length, level); + } + +/************************************************* +* Create an OctetString from a hex string * +*************************************************/ +void OctetString::change(const std::string& hex_string) + { + SecureVector hex; + for(u32bit j = 0; j != hex_string.length(); j++) + if(Hex_Decoder::is_valid(hex_string[j])) + hex.append(hex_string[j]); + + if(hex.size() % 2 != 0) + throw Invalid_Argument("OctetString: hex string must encode full bytes"); + bits.create(hex.size() / 2); + for(u32bit j = 0; j != bits.size(); j++) + bits[j] = Hex_Decoder::decode(hex.begin() + 2*j); + } + +/************************************************* +* Create an OctetString from a byte string * +*************************************************/ +void OctetString::change(const byte in[], u32bit n) + { + bits.create(n); + bits.copy(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(u32bit j = 0; j != bits.size(); j++) + bits[j] = ODD_PARITY[bits[j]]; + } + +/************************************************* +* Hex encode an OctetString * +*************************************************/ +std::string OctetString::as_string() const + { + Pipe pipe(new Hex_Encoder); + pipe.process_msg(bits); + return pipe.read_all_as_string(); + } + +/************************************************* +* XOR Operation for OctetStrings * +*************************************************/ +OctetString& OctetString::operator^=(const OctetString& k) + { + if(&k == this) { bits.clear(); return (*this); } + xor_buf(bits.begin(), 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) + { + return OctetString(SecureVector(k1.bits_of(), k2.bits_of())); + } + +/************************************************* +* XOR Operation for OctetStrings * +*************************************************/ +OctetString operator^(const OctetString& k1, const OctetString& k2) + { + SecureVector ret(std::max(k1.length(), k2.length())); + ret.copy(k1.begin(), k1.length()); + xor_buf(ret, k2.begin(), k2.length()); + return OctetString(ret); + } + +} --- botan/symkey.h +++ botan/symkey.h @@ -0,0 +1,83 @@ +/************************************************* +* OctetString Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_SYMKEY_H__ +#define BOTAN_SYMKEY_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Octet String * +*************************************************/ +class OctetString + { + public: + u32bit length() const { return bits.size(); } + SecureVector bits_of() const { return bits; } + + const byte* begin() const { return bits.begin(); } + const byte* end() const { return bits.end(); } + + std::string as_string() const; + + OctetString& operator^=(const OctetString&); + + void set_odd_parity(); + + void change(u32bit, RNG_Quality); + void change(const std::string&); + void change(const byte[], u32bit); + void change(const MemoryRegion& in) { bits = in; } + + OctetString(const std::string& str = "") { change(str); } + OctetString(const byte in[], u32bit len) { change(in, len); } + OctetString(const MemoryRegion& in) { change(in); } + private: + SecureVector bits; + }; + +/************************************************* +* Operations on Octet Strings * +*************************************************/ +bool operator==(const OctetString&, const OctetString&); +bool operator!=(const OctetString&, const OctetString&); +OctetString operator+(const OctetString&, const OctetString&); +OctetString operator^(const OctetString&, const OctetString&); + +/************************************************* +* Symmetric Key * +*************************************************/ +class SymmetricKey : public OctetString + { + public: + void change(u32bit n) { OctetString::change(n, SessionKey); } + SymmetricKey(u32bit len) { change(len); } + SymmetricKey(const std::string& str = "") : OctetString(str) {} + SymmetricKey(const byte in[], u32bit l) : OctetString(in, l) {} + SymmetricKey(const MemoryRegion& in) : OctetString(in) {} + SymmetricKey(const OctetString& os) : OctetString(os) {} + }; + +/************************************************* +* Initialization Vector * +*************************************************/ +class InitializationVector : public OctetString + { + public: + void change(u32bit n) { OctetString::change(n, Nonce); } + InitializationVector(u32bit len) { change(len); } + InitializationVector(const std::string& str = "") : OctetString(str) {} + InitializationVector(const byte in[], u32bit l) : OctetString(in, l) {} + InitializationVector(const MemoryRegion& in) : OctetString(in) {} + InitializationVector(const OctetString& os) : OctetString(os) {} + }; + +} + +#endif --- botan/thanks.txt +++ botan/thanks.txt @@ -0,0 +1,46 @@ +The following people have contributed substantial patches: + + Peter J. Jones: Wrote the initial version of the comp_bzip2 module + Justin Karneges: Contributed the mux_qt module + Hany Greiss: Windows port + +AEP Systems Ltd kindly provided an AEP2000 crypto card and drivers, enabling +the creation of Botan's AEP engine module. + +The author would also like to thank the following people for contributing bug +reports, useful information, or other assistance: + + Darren Starsmore + Dan Nicolaescu + Dominik Vogt + Hany Greiss + James Widener + Jeff B + Ken Perano + Ying-Chieh Liao + Vaclav Ovsik + +In addition, the following people have unknowingly contributed help: + + The implementation of DES is based off a public domain implementation by Phil + Karn from 1994 (he, in turn, credits Richard Outerbridge and Jim Gillogly). + + Rijndael and Square are based on the reference implementations written by + the inventors, Joan Daemen and Vincent Rijmen. + + The Serpent S-boxes used were discovered by Dag Arne Osvik and detailed in + his paper "Speeding Up Serpent". + + Matthew Skala's public domain twofish.c (as given in GnuPG 0.9.8) provided + the basis for my Twofish code (particularly the key schedule). + + Some of the hash functions (MD5, SHA-1, etc) use an optimized implementation + of one of the boolean functions, which was discovered by Colin Plumb. + + The design of Randpool takes some of it's design principles from those + suggested by Eric A. Young in his SSLeay documentation and Peter Gutmann's + paper "Software Generation of Practically Strong Random Numbers". + + ANSI_X917_RNG's design was changed from the X9.17 standard in response to the + attacks presented in the paper "Cryptanalytic Attacks on Pseudorandom Number + Generators", by Kelsey, Schneier, Wagner, and Hall. --- botan/timers.cpp +++ botan/timers.cpp @@ -0,0 +1,47 @@ +/************************************************* +* Timestamp Functions Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +Timer* global_timer = 0; + +} + +/************************************************* +* Timer Access Functions * +*************************************************/ +u64bit system_time() + { + return std::time(0); + } + +u64bit system_clock() + { + if(!global_timer) + return combine_timers(std::time(0), std::clock(), CLOCKS_PER_SEC); + return global_timer->clock(); + } + +namespace Init { + +/************************************************* +* Set the Timer type * +*************************************************/ +void set_timer_type(Timer* timer) + { + delete global_timer; + global_timer = timer; + } + +} + +} --- botan/timers.h +++ botan/timers.h @@ -0,0 +1,25 @@ +/************************************************* +* Timestamp Functions Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_TIMERS_H__ +#define BOTAN_TIMERS_H__ + +#include + +namespace Botan { + +/************************************************* +* Timer Interface * +*************************************************/ +class Timer + { + public: + virtual u64bit clock() const = 0; + virtual ~Timer() {} + }; + +} + +#endif --- botan/types.h +++ botan/types.h @@ -0,0 +1,36 @@ +/************************************************* +* Low Level Types Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_TYPES_H__ +#define BOTAN_TYPES_H__ + +namespace Botan { + +typedef unsigned char byte; +typedef unsigned short u16bit; +typedef unsigned int u32bit; + +typedef signed int s32bit; + +#if defined(_MSC_VER) || defined(__BORLANDC__) + typedef unsigned __int64 u64bit; +#elif defined(__KCC) + typedef unsigned __long_long u64bit; +#elif defined(__GNUG__) + __extension__ typedef unsigned long long u64bit; +#else + typedef unsigned long long u64bit; +#endif + +} + +namespace Botan_types { + +typedef Botan::byte byte; +typedef Botan::u32bit u32bit; + +} + +#endif --- botan/ui.cpp +++ botan/ui.cpp @@ -0,0 +1,62 @@ +/************************************************* +* User Interface Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include + +namespace Botan { + +/************************************************* +* Get a passphrase from the user * +*************************************************/ +std::string User_Interface::get_passphrase(const std::string&, + const std::string&, + UI_Result& action) const + { + action = OK; + + if(!first_try) + action = CANCEL_ACTION; + + return preset_passphrase; + } + +/************************************************* +* User_Interface Constructor * +*************************************************/ +User_Interface::User_Interface(const std::string& preset) : + preset_passphrase(preset) + { + first_try = true; + } + +namespace UI { + +/************************************************* +* The current pulse function * +*************************************************/ +pulse_func pulse_f = 0; +void* pulse_f_data = 0; + +/************************************************* +* Set the UI pulse function * +*************************************************/ +void set_pulse(pulse_func p, void* p_data) + { + pulse_f = p; + pulse_f_data = p_data; + } + +/************************************************* +* Call the UI pulse function * +*************************************************/ +void pulse(Pulse_Type type) + { + if(pulse_f) + pulse_f(type, pulse_f_data); + } + +} + +} --- botan/ui.h +++ botan/ui.h @@ -0,0 +1,63 @@ +/************************************************* +* User Interface Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_UI_H__ +#define BOTAN_UI_H__ + +#include + +namespace Botan { + +/************************************************* +* User Interface * +*************************************************/ +class User_Interface + { + public: + enum UI_Result { OK, CANCEL_ACTION }; + + virtual std::string get_passphrase(const std::string&, + const std::string&, + UI_Result&) const; + User_Interface(const std::string& = ""); + virtual ~User_Interface() {} + protected: + const std::string preset_passphrase; + mutable bool first_try; + }; + +namespace UI { + +/************************************************* +* Pulse Function * +*************************************************/ +enum Pulse_Type { + GENERAL_PULSE, + + PIPE_WRITE, + + PRIME_SEARCHING, + PRIME_SIEVING, + PRIME_PASSED_SIEVE, + PRIME_TESTING, + PRIME_FOUND +}; +typedef void (*pulse_func)(Pulse_Type, void*); + +/************************************************* +* Set the UI pulse function * +*************************************************/ +void set_pulse(pulse_func, void* = 0); + +/************************************************* +* Call the UI pulse function * +*************************************************/ +void pulse(Pulse_Type = GENERAL_PULSE); + +} + +} + +#endif --- botan/util.cpp +++ botan/util.cpp @@ -0,0 +1,339 @@ +/************************************************* +* Utility Functions Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* XOR arrays together * +*************************************************/ +void xor_buf(byte data[], const byte mask[], u32bit length) + { + while(length >= 8) + { + data[0] ^= mask[0]; data[1] ^= mask[1]; + data[2] ^= mask[2]; data[3] ^= mask[3]; + data[4] ^= mask[4]; data[5] ^= mask[5]; + data[6] ^= mask[6]; data[7] ^= mask[7]; + data += 8; mask += 8; length -= 8; + } + for(u32bit j = 0; j != length; j++) + data[j] ^= mask[j]; + } + +void xor_buf(byte out[], const byte in[], const byte mask[], u32bit length) + { + while(length >= 8) + { + out[0] = in[0] ^ mask[0]; out[1] = in[1] ^ mask[1]; + out[2] = in[2] ^ mask[2]; out[3] = in[3] ^ mask[3]; + out[4] = in[4] ^ mask[4]; out[5] = in[5] ^ mask[5]; + out[6] = in[6] ^ mask[6]; out[7] = in[7] ^ mask[7]; + in += 8; out += 8; mask += 8; length -= 8; + } + for(u32bit j = 0; j != length; j++) + out[j] = in[j] ^ mask[j]; + } + +/************************************************* +* Byte Reversal Functions * +*************************************************/ +u16bit reverse_bytes(u16bit input) + { + return rotate_left(input, 8); + } + +u32bit reverse_bytes(u32bit input) + { + input = ((input & 0xFF00FF00) >> 8) | ((input & 0x00FF00FF) << 8); + return rotate_left(input, 16); + } + +u64bit reverse_bytes(u64bit input) + { + input = ((input & 0xFF00FF00FF00FF00ULL) >> 8) | + ((input & 0x00FF00FF00FF00FFULL) << 8); + input = ((input & 0xFFFF0000FFFF0000ULL) >> 16) | + ((input & 0x0000FFFF0000FFFFULL) << 16); + return rotate_left(input, 32); + } + +/************************************************* +* Bit Reversal Functions * +*************************************************/ +byte reverse_bits(byte input) + { + input = ((input & 0xAA) >> 1) | ((input & 0x55) << 1); + input = ((input & 0xCC) >> 2) | ((input & 0x33) << 2); + return rotate_left(input, 4); + } + +u16bit reverse_bits(u16bit input) + { + input = ((input & 0xAAAA) >> 1) | ((input & 0x5555) << 1); + input = ((input & 0xCCCC) >> 2) | ((input & 0x3333) << 2); + input = ((input & 0xF0F0) >> 4) | ((input & 0x0F0F) << 4); + return reverse_bytes(input); + } + +u32bit reverse_bits(u32bit input) + { + input = ((input & 0xAAAAAAAA) >> 1) | ((input & 0x55555555) << 1); + input = ((input & 0xCCCCCCCC) >> 2) | ((input & 0x33333333) << 2); + input = ((input & 0xF0F0F0F0) >> 4) | ((input & 0x0F0F0F0F) << 4); + return reverse_bytes(input); + } + +u64bit reverse_bits(u64bit input) + { + input = ((input & 0xAAAAAAAAAAAAAAAAULL) >> 1) | + ((input & 0x5555555555555555ULL) << 1); + input = ((input & 0xCCCCCCCCCCCCCCCCULL) >> 2) | + ((input & 0x3333333333333333ULL) << 2); + input = ((input & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | + ((input & 0x0F0F0F0F0F0F0F0FULL) << 4); + return reverse_bytes(input); + } + +/************************************************* +* Return true iff arg is 2**n for some n > 0 * +*************************************************/ +bool power_of_2(u64bit arg) + { + if(arg == 0 || arg == 1) + return false; + if((arg & (arg-1)) == 0) + return true; + return false; + } + +/************************************************* +* Combine a two time values into a single one * +*************************************************/ +u64bit combine_timers(u32bit seconds, u32bit parts, u32bit parts_hz) + { + const u64bit NANOSECONDS_UNITS = 1000000000; + parts *= (NANOSECONDS_UNITS / parts_hz); + return ((seconds * NANOSECONDS_UNITS) + parts); + } + +/************************************************* +* Return the index of the highest set bit * +*************************************************/ +u32bit high_bit(u64bit n) + { + for(u32bit count = 64; count > 0; count--) + if((n >> (count - 1)) & 0x01) + return count; + return 0; + } + +/************************************************* +* Return the index of the lowest set bit * +*************************************************/ +u32bit low_bit(u64bit n) + { + for(u32bit count = 0; count != 64; count++) + if((n >> count) & 0x01) + return (count + 1); + return 0; + } + +/************************************************* +* Return the number of significant bytes in n * +*************************************************/ +u32bit significant_bytes(u64bit n) + { + for(u32bit j = 0; j != 8; j++) + if(get_byte(j, n)) + return 8-j; + return 0; + } + +/************************************************* +* Return the Hamming weight of n * +*************************************************/ +u32bit hamming_weight(u64bit n) + { + u32bit weight = 0; + for(u32bit j = 0; j != 64; j++) + if((n >> j) & 0x01) + weight++; + return weight; + } + +/************************************************* +* Round up n to multiple of align_to * +*************************************************/ +u32bit round_up(u32bit n, u32bit align_to) + { + if(n % align_to || n == 0) + n += align_to - (n % align_to); + return n; + } + +/************************************************* +* Round down n to multiple of align_to * +*************************************************/ +u32bit round_down(u32bit n, u32bit align_to) + { + return (n - (n % align_to)); + } + +/************************************************* +* Return the work required for solving DL * +*************************************************/ +u32bit dl_work_factor(u32bit n_bits) + { + const u32bit MIN_ESTIMATE = 64; + + if(n_bits < 32) + return 0; + + const double log_x = n_bits / 1.44; + + u32bit estimate = (u32bit)(2.76 * std::pow(log_x, 1.0/3.0) * + std::pow(std::log(log_x), 2.0/3.0)); + + return std::max(estimate, MIN_ESTIMATE); + } + +/************************************************* +* Convert an integer into a string * +*************************************************/ +std::string to_string(u64bit n, u32bit min_len) + { + std::string lenstr; + if(n) + { + while(n > 0) + { + lenstr = digit2char(n % 10) + lenstr; + n /= 10; + } + } + else + lenstr = "0"; + + while(lenstr.size() < min_len) + lenstr = "0" + lenstr; + + return lenstr; + } + +/************************************************* +* Convert an integer into a string * +*************************************************/ +u32bit to_u32bit(const std::string& number) + { + u32bit n = 0; + + for(std::string::const_iterator j = number.begin(); j != number.end(); j++) + { + const u32bit OVERFLOW_MARK = 0xFFFFFFFF / 10; + + byte digit = char2digit(*j); + + if((n > OVERFLOW_MARK) || (n == OVERFLOW_MARK && digit > 5)) + throw Decoding_Error("to_u32bit: Integer overflow"); + n *= 10; + n += digit; + } + return n; + } + +/************************************************* +* 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) + { + if(c == '0') return 0; + if(c == '1') return 1; + if(c == '2') return 2; + if(c == '3') return 3; + if(c == '4') return 4; + if(c == '5') return 5; + if(c == '6') return 6; + if(c == '7') return 7; + if(c == '8') return 8; + if(c == '9') return 9; + throw Invalid_Argument("char2digit: Invalid decimal char " + c); + } + +/************************************************* +* Convert a digit to a character * +*************************************************/ +char digit2char(byte b) + { + if(b == 0) return '0'; + if(b == 1) return '1'; + if(b == 2) return '2'; + if(b == 3) return '3'; + if(b == 4) return '4'; + if(b == 5) return '5'; + if(b == 6) return '6'; + if(b == 7) return '7'; + if(b == 8) return '8'; + if(b == 9) return '9'; + throw Invalid_Argument("digit2char: Input is not a digit"); + } + +/************************************************* +* Estimate the entropy of the buffer * +*************************************************/ +u32bit entropy_estimate(const byte buffer[], u32bit length) + { + if(length <= 4) + return 0; + + u32bit estimate = 0; + byte last = 0, last_delta = 0, last_delta2 = 0; + + for(u32bit j = 0; j != length; j++) + { + byte delta = last ^ buffer[j]; + last = buffer[j]; + + byte delta2 = delta ^ last_delta; + last_delta = delta; + + byte delta3 = delta2 ^ last_delta2; + last_delta2 = delta2; + + byte min_delta = delta; + if(min_delta > delta2) min_delta = delta2; + if(min_delta > delta3) min_delta = delta3; + + estimate += hamming_weight(min_delta); + } + + return (estimate / 2); + } + +} --- botan/util.h +++ botan/util.h @@ -0,0 +1,140 @@ +/************************************************* +* Utility Functions Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_UTIL_H__ +#define BOTAN_UTIL_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Rotation Functions * +*************************************************/ +template inline T rotate_left(T input, u32bit rot) + { return (T)((input << rot) | (input >> (8*sizeof(T)-rot))); } + +template inline T rotate_right(T input, u32bit rot) + { return (T)((input >> rot) | (input << (8*sizeof(T)-rot))); } + +/************************************************* +* Byte Extraction Function * +*************************************************/ +template inline byte get_byte(u32bit byte_num, T input) + { return (byte)(input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3)); } + +/************************************************* +* Byte to Word Conversions * +*************************************************/ +inline u16bit make_u16bit(byte input0, byte input1) + { return (u16bit)(((u16bit)input0 << 8) | input1); } + +inline u32bit make_u32bit(byte input0, byte input1, byte input2, byte input3) + { return (u32bit)(((u32bit)input0 << 24) | ((u32bit)input1 << 16) | + ((u32bit)input2 << 8) | input3); } + +inline u64bit make_u64bit(byte input0, byte input1, byte input2, byte input3, + byte input4, byte input5, byte input6, byte input7) + { + return (u64bit)(((u64bit)input0 << 56) | ((u64bit)input1 << 48) | + ((u64bit)input2 << 40) | ((u64bit)input3 << 32) | + ((u64bit)input4 << 24) | ((u64bit)input5 << 16) | + ((u64bit)input6 << 8) | input7); + } + +/************************************************* +* XOR Functions * +*************************************************/ +void xor_buf(byte[], const byte[], u32bit); +void xor_buf(byte[], const byte[], const byte[], u32bit); + +/************************************************* +* Byte Swapping Functions * +*************************************************/ +u16bit reverse_bytes(u16bit); +u32bit reverse_bytes(u32bit); +u64bit reverse_bytes(u64bit); + +/************************************************* +* Bit Swapping Functions * +*************************************************/ +byte reverse_bits(byte); +u16bit reverse_bits(u16bit); +u32bit reverse_bits(u32bit); +u64bit reverse_bits(u64bit); + +/************************************************* +* Timer Access Functions * +*************************************************/ +u64bit system_time(); +u64bit system_clock(); + +/************************************************* +* Memory Locking Functions * +*************************************************/ +void lock_mem(void*, u32bit); +void unlock_mem(void*, u32bit); + +/************************************************* +* Parsing functions * +*************************************************/ +std::vector parse_algorithm_name(const std::string&); +std::vector split_on(const std::string&, char); +std::vector parse_asn1_oid(const std::string&); +bool x500_name_cmp(const std::string&, const std::string&); + +/************************************************* +* Misc Utility Functions * +*************************************************/ +bool power_of_2(u64bit); +u32bit high_bit(u64bit); +u32bit low_bit(u64bit); +u32bit significant_bytes(u64bit); +u32bit hamming_weight(u64bit); +u32bit round_up(u32bit, u32bit); +u32bit round_down(u32bit, u32bit); +u64bit combine_timers(u32bit, u32bit, u32bit); + +/************************************************* +* Work Factor Estimates * +*************************************************/ +u32bit entropy_estimate(const byte[], u32bit); +u32bit dl_work_factor(u32bit); + +/************************************************* +* String/Integer Conversions * +*************************************************/ +std::string to_string(u64bit, u32bit = 0); +u32bit to_u32bit(const std::string&); + +/************************************************* +* Character Set Handling * +*************************************************/ +bool is_digit(char); +bool is_space(char); +char to_lower(char); + +byte char2digit(char); +char digit2char(byte); + +std::string local2iso(const std::string&); +std::string iso2local(const std::string&); + +std::string utf2iso(const std::string&); +std::string iso2utf(const std::string&); + +/************************************************* +* Return the values of various defined HashIDs * +*************************************************/ +MemoryVector pkcs_hash_id(const std::string&); +byte ieee1363_hash_id(const std::string&); + +} + +#endif --- botan/version.h +++ botan/version.h @@ -0,0 +1,34 @@ +/************************************************* +* Version Information Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_VERSION_H__ +#define BOTAN_VERSION_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Get information describing the version * +*************************************************/ +std::string version_string(); +u32bit version_major(); +u32bit version_minor(); +u32bit version_patch(); + +/************************************************* +* Macros for compile-time version checks * +*************************************************/ +#define BOTAN_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +#define BOTAN_VERSION_CODE BOTAN_VERSION_CODE_FOR(BOTAN_VERSION_MAJOR, \ + BOTAN_VERSION_MINOR, \ + BOTAN_VERSION_PATCH) + +} + +#endif --- botan/x509_ca.cpp +++ botan/x509_ca.cpp @@ -0,0 +1,366 @@ +/************************************************* +* X.509 Certificate Authority Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Load the certificate and private key * +*************************************************/ +MemoryVector make_SKID(const MemoryRegion& pub_key) + { + std::auto_ptr hash(get_hash("SHA-1")); + return hash->process(pub_key); + } + +} + +/************************************************* +* Load the certificate and private key * +*************************************************/ +X509_CA::X509_CA(const X509_Certificate& c, + const PKCS8_PrivateKey& key) : cert(c) + { + const PKCS8_PrivateKey* key_pointer = &key; + if(!dynamic_cast(key_pointer)) + throw Invalid_Argument("X509_CA: " + key.algo_name() + " cannot sign"); + + if(!cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + std::string padding; + Signature_Format format; + + Config::choose_sig_format(key.algo_name(), padding, format); + + ca_sig_algo.oid = OIDS::lookup(key.algo_name() + "/" + padding); + ca_sig_algo.parameters = key.DER_encode_params(); + + const PK_Signing_Key& sig_key = dynamic_cast(key); + signer = get_pk_signer(sig_key, padding, format); + } + +/************************************************* +* Sign a PKCS #10 certificate request * +*************************************************/ +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + u32bit expire_time) const + { + if(req.is_CA() && !Config::get_bool("x509/ca/allow_ca")) + throw Policy_Violation("X509_CA: Attempted to sign new CA certificate"); + + Key_Constraints constraints; + if(req.is_CA()) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + { + std::auto_ptr key(req.subject_public_key()); + constraints = X509::find_constraints(*key, req.constraints()); + } + + if(expire_time == 0) + expire_time = Config::get_time("x509/ca/default_expire"); + + const u64bit current_time = system_time(); + + X509_Time not_before(current_time); + X509_Time not_after(current_time + expire_time); + + return make_cert(signer, ca_sig_algo, req.raw_public_key(), + cert.subject_key_id(), not_before, not_after, + cert.subject_dn(), req.subject_dn(), + req.is_CA(), req.path_limit(), req.subject_alt_name(), + constraints, req.ex_constraints()); + } + +/************************************************* +* Create a new certificate * +*************************************************/ +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + const AlgorithmIdentifier& sig_algo, + const MemoryRegion& pub_key, + const MemoryRegion& auth_key_id, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + bool is_CA, u32bit path_limit, + const AlternativeName& subject_alt, + Key_Constraints constraints, + const std::vector& ex_constraints) + { + const u32bit X509_CERT_VERSION = 2; + const u32bit SERIAL_BITS = 128; + + DER_Encoder tbs_cert; + + tbs_cert.start_sequence(); + tbs_cert.start_explicit(ASN1_Tag(0)); + DER::encode(tbs_cert, X509_CERT_VERSION); + tbs_cert.end_explicit(ASN1_Tag(0)); + + DER::encode(tbs_cert, random_integer(SERIAL_BITS, Nonce)); + DER::encode(tbs_cert, sig_algo); + DER::encode(tbs_cert, issuer_dn); + tbs_cert.start_sequence(); + DER::encode(tbs_cert, not_before); + DER::encode(tbs_cert, not_after); + tbs_cert.end_sequence(); + DER::encode(tbs_cert, subject_dn); + tbs_cert.add_raw_octets(pub_key); + + tbs_cert.start_explicit(ASN1_Tag(3)); + tbs_cert.start_sequence(); + + DER_Encoder v3_ext; + + DER::encode(v3_ext, make_SKID(pub_key), OCTET_STRING); + do_ext(tbs_cert, v3_ext, "X509v3.SubjectKeyIdentifier", "subject_key_id"); + + if(auth_key_id.size()) + { + v3_ext.start_sequence(); + DER::encode(v3_ext, auth_key_id, OCTET_STRING, + ASN1_Tag(0), CONTEXT_SPECIFIC); + v3_ext.end_sequence(); + do_ext(tbs_cert, v3_ext, "X509v3.AuthorityKeyIdentifier", + "authority_key_id"); + } + + if(is_CA || (Config::get_string("x509/ca/basic_constraints") == "always")) + { + v3_ext.start_sequence(); + if(is_CA) + { + DER::encode(v3_ext, true); + if(path_limit != NO_CERT_PATH_LIMIT) + DER::encode(v3_ext, path_limit); + } + v3_ext.end_sequence(); + do_ext(tbs_cert, v3_ext, "X509v3.BasicConstraints", "basic_constraints"); + } + + if(subject_alt.has_items()) + { + DER::encode(v3_ext, subject_alt); + do_ext(tbs_cert, v3_ext, "X509v3.SubjectAlternativeName", + "subject_alternative_name"); + } + + if(constraints != NO_CONSTRAINTS) + { + DER::encode(v3_ext, constraints); + do_ext(tbs_cert, v3_ext, "X509v3.KeyUsage", "key_usage"); + } + + if(ex_constraints.size()) + { + v3_ext.start_sequence(); + for(u32bit j = 0; j != ex_constraints.size(); j++) + DER::encode(v3_ext, ex_constraints[j]); + v3_ext.end_sequence(); + do_ext(tbs_cert, v3_ext, "X509v3.ExtendedKeyUsage", + "extended_key_usage"); + } + + tbs_cert.end_sequence(); + tbs_cert.end_explicit(ASN1_Tag(3)); + tbs_cert.end_sequence(); + + MemoryVector tbs_bits = tbs_cert.get_contents(); + MemoryVector sig = signer->sign_message(tbs_bits); + + DER_Encoder full_cert; + full_cert.start_sequence(); + full_cert.add_raw_octets(tbs_bits); + DER::encode(full_cert, sig_algo); + DER::encode(full_cert, sig, BIT_STRING); + full_cert.end_sequence(); + + DataSource_Memory source(full_cert.get_contents()); + + return X509_Certificate(source); + } + +/************************************************* +* Handle encoding a v3 extension * +*************************************************/ +void X509_CA::do_ext(DER_Encoder& new_cert, DER_Encoder& extension, + const std::string& oid, const std::string& opt) + { + std::string EXT_SETTING = "yes"; + + if(opt != "") + { + EXT_SETTING = Config::get_string("x509/exts/" + opt); + + if(EXT_SETTING == "") + throw Exception("X509_CA: No policy setting for using " + oid); + } + + if(EXT_SETTING == "no") + return; + else if(EXT_SETTING == "yes" || EXT_SETTING == "noncritical" || + EXT_SETTING == "critical") + { + Extension extn(oid, extension.get_contents()); + if(EXT_SETTING == "critical") + extn.critical = true; + DER::encode(new_cert, extn); + } + else + throw Invalid_Argument("X509_CA:: Invalid value for option x509/exts/" + + opt + " of " + EXT_SETTING); + } + +/************************************************* +* Create a new, empty CRL * +*************************************************/ +X509_CRL X509_CA::new_crl(u32bit next_update) const + { + std::vector empty; + return make_crl(empty, 1, next_update); + } + +/************************************************* +* Update a CRL with new entries * +*************************************************/ +X509_CRL X509_CA::update_crl(const X509_CRL& crl, + const std::vector& new_revoked, + u32bit next_update) const + { + std::vector already_revoked = crl.get_revoked(); + std::vector all_revoked; + + X509_Store store; + store.add_cert(cert, true); + if(store.add_crl(crl) != VERIFIED) + throw Invalid_Argument("X509_CA::update_crl: Invalid CRL provided"); + + std::map, bool> removed_from_crl; + for(u32bit j = 0; j != new_revoked.size(); j++) + { + if(new_revoked[j].reason == DELETE_CRL_ENTRY) + removed_from_crl[new_revoked[j].serial] = true; + else + all_revoked.push_back(new_revoked[j]); + } + + for(u32bit j = 0; j != already_revoked.size(); j++) + { + std::map, bool>::const_iterator i; + i = removed_from_crl.find(already_revoked[j].serial); + + if(i == removed_from_crl.end()) + all_revoked.push_back(already_revoked[j]); + } + + std::vector cert_list; + std::sort(all_revoked.begin(), all_revoked.end()); + std::unique_copy(all_revoked.begin(), all_revoked.end(), + std::back_inserter(cert_list)); + + return make_crl(cert_list, crl.crl_number() + 1, next_update); + } + +/************************************************* +* Create a CRL * +*************************************************/ +X509_CRL X509_CA::make_crl(const std::vector& revoked, + u32bit crl_number, u32bit next_update) const + { + const u32bit X509_CRL_VERSION = 1; + + if(next_update == 0) + next_update = Config::get_time("x509/crl/next_update"); + + DER_Encoder tbs_crl; + + const u64bit current_time = system_time(); + + tbs_crl.start_sequence(); + DER::encode(tbs_crl, X509_CRL_VERSION); + DER::encode(tbs_crl, ca_sig_algo); + DER::encode(tbs_crl, cert.subject_dn()); + DER::encode(tbs_crl, X509_Time(current_time)); + DER::encode(tbs_crl, X509_Time(current_time + next_update)); + + if(revoked.size()) + { + tbs_crl.start_sequence(); + for(u32bit j = 0; j != revoked.size(); j++) + DER::encode(tbs_crl, revoked[j]); + tbs_crl.end_sequence(); + } + + tbs_crl.start_explicit(ASN1_Tag(0)); + tbs_crl.start_sequence(); + + DER_Encoder crl_ext; + + if(cert.subject_key_id().size()) + { + crl_ext.start_sequence(); + crl_ext.start_explicit(ASN1_Tag(0)); + DER::encode(crl_ext, cert.subject_key_id(), OCTET_STRING); + crl_ext.end_explicit(ASN1_Tag(0)); + crl_ext.end_sequence(); + do_ext(tbs_crl, crl_ext, "X509v3.AuthorityKeyIdentifier", + "authority_key_id"); + } + + if(crl_number) + { + DER::encode(crl_ext, crl_number); + do_ext(tbs_crl, crl_ext, "X509v3.CRLNumber", "crl_number"); + } + + tbs_crl.end_sequence(); + tbs_crl.end_explicit(ASN1_Tag(0)); + tbs_crl.end_sequence(); + + MemoryVector tbs_bits = tbs_crl.get_contents(); + MemoryVector sig = signer->sign_message(tbs_bits); + + DER_Encoder full_crl; + full_crl.start_sequence(); + full_crl.add_raw_octets(tbs_bits); + DER::encode(full_crl, ca_sig_algo); + DER::encode(full_crl, sig, BIT_STRING); + full_crl.end_sequence(); + + DataSource_Memory source(full_crl.get_contents()); + + return X509_CRL(source); + } + +/************************************************* +* Return the CA's certificate * +*************************************************/ +X509_Certificate X509_CA::ca_certificate() const + { + return cert; + } + +/************************************************* +* X509_CA Destructor * +*************************************************/ +X509_CA::~X509_CA() + { + delete signer; + } + +} --- botan/x509_ca.h +++ botan/x509_ca.h @@ -0,0 +1,58 @@ +/************************************************* +* X.509 Certificate Authority Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_CA_H__ +#define BOTAN_X509_CA_H__ + +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* X.509 Certificate Authority * +*************************************************/ +class X509_CA + { + public: + X509_Certificate sign_request(const PKCS10_Request&, u32bit = 0) const; + + X509_Certificate ca_certificate() const; + + X509_CRL new_crl(u32bit = 0) const; + X509_CRL update_crl(const X509_CRL&, const std::vector&, + u32bit = 0) const; + + static X509_Certificate make_cert(PK_Signer*, const AlgorithmIdentifier&, + const MemoryRegion&, + const MemoryRegion&, + const X509_Time&, const X509_Time&, + const X509_DN&, const X509_DN&, + bool, u32bit, const AlternativeName&, + Key_Constraints, + const std::vector&); + + static void do_ext(DER_Encoder&, DER_Encoder&, + const std::string&, const std::string&); + + X509_CA(const X509_Certificate&, const PKCS8_PrivateKey&); + ~X509_CA(); + private: + X509_CA(const X509_CA&) {} + X509_CA& operator=(const X509_CA&) { return (*this); } + + X509_CRL make_crl(const std::vector&, u32bit, u32bit) const; + + AlgorithmIdentifier ca_sig_algo; + X509_Certificate cert; + PK_Signer* signer; + }; + +} + +#endif --- botan/x509_crl.cpp +++ botan/x509_crl.cpp @@ -0,0 +1,173 @@ +/************************************************* +* X.509 CRL Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Load a X.509 CRL * +*************************************************/ +X509_CRL::X509_CRL(DataSource& in) : X509_Object(in, "X509 CRL/CRL") + { + version = crl_count = 0; + + do_decode(); + } + +/************************************************* +* Load a X.509 CRL * +*************************************************/ +X509_CRL::X509_CRL(const std::string& in) : X509_Object(in, "CRL/X509 CRL") + { + version = crl_count = 0; + + do_decode(); + } + +/************************************************* +* Decode the TBSCertList data * +*************************************************/ +void X509_CRL::force_decode() + { + BER_Decoder tbs_crl(tbs_bits); + + BER::decode_optional(tbs_crl, version, INTEGER, UNIVERSAL); + + if(version != 0 && version != 1) + throw X509_CRL_Error("Unknown X.509 CRL version " + + to_string(version+1)); + + AlgorithmIdentifier sig_algo_inner; + BER::decode(tbs_crl, sig_algo_inner); + + if(sig_algo != sig_algo_inner) + throw X509_CRL_Error("Algorithm identifier mismatch"); + + BER::decode(tbs_crl, issuer); + BER::decode(tbs_crl, start); + BER::decode(tbs_crl, end); + + 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; + BER::decode(cert_list, 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); + BER_Decoder sequence = BER::get_subsequence(crl_options); + + while(sequence.more_items()) + { + Extension extn; + BER::decode(sequence, extn); + handle_crl_extension(extn); + } + next = tbs_crl.get_next_object(); + } + + if(next.type_tag != NO_OBJECT) + throw X509_CRL_Error("Unknown tag in CRL"); + + tbs_crl.verify_end(); + } + +/************************************************* +* Decode a CRL extension * +*************************************************/ +void X509_CRL::handle_crl_extension(const Extension& extn) + { + BER_Decoder value(extn.value); + + if(extn.oid == OIDS::lookup("X509v3.AuthorityKeyIdentifier")) + { + BER_Decoder key_id = BER::get_subsequence(value); + BER::decode_optional_string(key_id, issuer_key_id, OCTET_STRING, + ASN1_Tag(0), CONTEXT_SPECIFIC); + } + else if(extn.oid == OIDS::lookup("X509v3.CRLNumber")) + BER::decode(value, crl_count); + else + { + if(extn.critical) + { + std::string action = Config::get_string("x509/crl/unknown_critical"); + if(action == "throw") + throw X509_CRL_Error("Unknown critical CRL extension " + + extn.oid.as_string()); + else if(action != "ignore") + throw Invalid_Argument("Bad value of x509/crl/unknown_critical: " + + action); + } + return; + } + + value.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 issuer; + } + +/************************************************* +* Return the key identifier of the issuer * +*************************************************/ +MemoryVector X509_CRL::authority_key_id() const + { + return issuer_key_id; + } + +/************************************************* +* Return the CRL number of this CRL * +*************************************************/ +u32bit X509_CRL::crl_number() const + { + return crl_count; + } + +/************************************************* +* Return the issue data of the CRL * +*************************************************/ +X509_Time X509_CRL::this_update() const + { + return start; + } + +/************************************************* +* Return the date when a new CRL will be issued * +*************************************************/ +X509_Time X509_CRL::next_update() const + { + return end; + } + +} --- botan/x509_crl.h +++ botan/x509_crl.h @@ -0,0 +1,51 @@ +/************************************************* +* X.509 CRL Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_CRL_H__ +#define BOTAN_X509_CRL_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* X.509 CRL * +*************************************************/ +class X509_CRL : public X509_Object + { + public: + struct X509_CRL_Error : public Exception + { + X509_CRL_Error(const std::string& error) : + Exception("X509_CRL: " + error) {} + }; + + std::vector get_revoked() const; + + X509_DN issuer_dn() const; + MemoryVector authority_key_id() const; + + u32bit crl_number() const; + X509_Time this_update() const; + X509_Time next_update() const; + + void force_decode(); + + X509_CRL(DataSource&); + X509_CRL(const std::string&); + private: + void handle_crl_extension(const Extension&); + std::vector revoked; + MemoryVector issuer_key_id; + X509_Time start, end; + X509_DN issuer; + u32bit version, crl_count; + }; + +} + +#endif --- botan/x509_key.cpp +++ botan/x509_key.cpp @@ -0,0 +1,196 @@ +/************************************************* +* X.509 Public Key Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/************************************************* +* Compute the key id * +*************************************************/ +u64bit X509_PublicKey::key_id() const + { + Pipe pipe(new Hash_Filter("SHA-1", 8)); + + pipe.start_msg(); + pipe.write(algo_name()); + pipe.write(DER_encode_pub()); + pipe.write(DER_encode_params()); + pipe.end_msg(); + + u64bit hash = 0; + for(u32bit j = 0; j != 8; j++) + { + byte next = 0; + if(pipe.read(next) != 1) + throw Internal_Error("X509_PublicKey::key_id: No more hash bits"); + hash = (hash << 8) | next; + } + return hash; + } + +namespace X509 { + +namespace { + +/************************************************* +* Extract the fields of a subjectPublicKeyInfo * +*************************************************/ +void X509_extract_info(DataSource& source, AlgorithmIdentifier& alg_id, + MemoryVector& key) + { + BER_Decoder decoder(source); + BER_Decoder sequence = BER::get_subsequence(decoder); + BER::decode(sequence, alg_id); + BER::decode(sequence, key, BIT_STRING); + sequence.verify_end(); + } + +} + +/************************************************* +* DER or PEM encode a X.509 public key * +*************************************************/ +void encode(const X509_PublicKey& key, Pipe& pipe, X509_Encoding encoding) + { + DER_Encoder encoder; + AlgorithmIdentifier alg_id(key.get_oid(), key.DER_encode_params()); + + encoder.start_sequence(); + DER::encode(encoder, alg_id); + DER::encode(encoder, key.DER_encode_pub(), BIT_STRING); + encoder.end_sequence(); + + MemoryVector der = encoder.get_contents(); + if(encoding == PEM) + pipe.write(PEM_Code::encode(der, "PUBLIC KEY")); + else + pipe.write(der); + } + +/************************************************* +* PEM encode a X.509 public key * +*************************************************/ +std::string PEM_encode(const X509_PublicKey& key) + { + Pipe pem; + pem.start_msg(); + encode(key, pem, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/************************************************* +* Extract a public key and return it * +*************************************************/ +X509_PublicKey* load_key(DataSource& source) + { + try { + AlgorithmIdentifier alg_id; + MemoryVector key; + + if(BER::maybe_BER(source) && !PEM_Code::matches(source)) + X509_extract_info(source, alg_id, key); + else + { + DataSource_Memory ber( + PEM_Code::decode_check_label(source, "PUBLIC KEY") + ); + X509_extract_info(ber, alg_id, key); + } + + if(key.is_empty()) + throw Decoding_Error("X.509 public key decoding failed"); + + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + + alg_id.oid.as_string()); + + std::auto_ptr key_obj(get_public_key(alg_name)); + if(!key_obj.get()) + throw Decoding_Error("Unknown PK algorithm/OID: " + alg_name + ", " + + alg_id.oid.as_string()); + + Pipe output; + output.process_msg(alg_id.parameters); + output.process_msg(key); + key_obj->BER_decode_params(output); + output.set_default_msg(1); + key_obj->BER_decode_pub(output); + + return key_obj.release(); + } + catch(Decoding_Error) + { + throw Decoding_Error("X.509 public key decoding failed"); + } + } + +/************************************************* +* Extract a public key and return it * +*************************************************/ +X509_PublicKey* load_key(const std::string& fsname) + { + DataSource_Stream source(fsname); + return X509::load_key(source); + } + +/************************************************* +* Extract a public key and return it * +*************************************************/ +X509_PublicKey* load_key(const MemoryRegion& mem) + { + DataSource_Memory source(mem); + return X509::load_key(source); + } + +/************************************************* +* Make a copy of this public key * +*************************************************/ +X509_PublicKey* copy_key(const X509_PublicKey& key) + { + Pipe bits; + bits.start_msg(); + X509::encode(key, bits, RAW_BER); + bits.end_msg(); + DataSource_Memory source(bits.read_all()); + return X509::load_key(source); + } + +/************************************************* +* Find the allowable key constraints * +*************************************************/ +Key_Constraints find_constraints(const X509_PublicKey& pub_key, + Key_Constraints limits) + { + const X509_PublicKey* key = &pub_key; + u32bit constraints = 0; + + if(dynamic_cast(key)) + constraints |= KEY_ENCIPHERMENT; + + if(dynamic_cast(key)) + constraints |= KEY_AGREEMENT; + + if(dynamic_cast(key) || + dynamic_cast(key)) + constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION; + + if(limits) + constraints &= limits; + + return Key_Constraints(constraints); + } + +} + +} --- botan/x509_key.h +++ botan/x509_key.h @@ -0,0 +1,48 @@ +/************************************************* +* X.509 Public Key Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_PUBLIC_KEY_H__ +#define BOTAN_X509_PUBLIC_KEY_H__ + +#include +#include + +namespace Botan { + +/************************************************* +* X.509 Public Key * +*************************************************/ +class X509_PublicKey : public virtual PK_Key + { + public: + u64bit key_id() const; + virtual MemoryVector DER_encode_pub() const = 0; + virtual MemoryVector DER_encode_params() const = 0; + virtual void BER_decode_pub(DataSource&) = 0; + virtual void BER_decode_params(DataSource&) = 0; + virtual ~X509_PublicKey() {} + }; + +namespace X509 { + +/************************************************* +* X.509 Public Key Encoding/Decoding * +*************************************************/ +void encode(const X509_PublicKey&, Pipe&, X509_Encoding = PEM); +std::string PEM_encode(const X509_PublicKey&); + +X509_PublicKey* load_key(DataSource&); +X509_PublicKey* load_key(const std::string&); +X509_PublicKey* load_key(const MemoryRegion&); + +X509_PublicKey* copy_key(const X509_PublicKey&); + +Key_Constraints find_constraints(const X509_PublicKey&, Key_Constraints); + +} + +} + +#endif --- botan/x509_obj.cpp +++ botan/x509_obj.cpp @@ -0,0 +1,164 @@ +/************************************************* +* X.509 SIGNED Object Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Create a generic X.509 object * +*************************************************/ +X509_Object::X509_Object(DataSource& stream, const std::string& labels) + { + init(stream, labels); + } + +/************************************************* +* Createa a generic X.509 object * +*************************************************/ +X509_Object::X509_Object(const std::string& file, const std::string& labels) + { + DataSource_Stream stream(file); + 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(BER::maybe_BER(in) && !PEM_Code::matches(in)) + decode_info(in); + 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); + decode_info(ber); + } + } + catch(Decoding_Error) + { + throw Decoding_Error(PEM_label_pref + " decoding failed"); + } + } + +/************************************************* +* Read a BER encoded X.509 object * +*************************************************/ +void X509_Object::decode_info(DataSource& source) + { + BER_Decoder ber(source); + BER_Decoder sequence = BER::get_subsequence(ber); + tbs_bits = BER::get_subsequence(sequence).get_remaining(); + + BER::decode(sequence, sig_algo); + BER::decode(sequence, sig, BIT_STRING); + sequence.verify_end(); + } + +/************************************************* +* Return a BER or PEM encoded X.509 object * +*************************************************/ +void X509_Object::encode(Pipe& out, X509_Encoding encoding) const + { + DER_Encoder encoder; + + encoder.start_sequence(); + encoder.add_raw_octets(tbs_data()); + DER::encode(encoder, sig_algo); + DER::encode(encoder, sig, BIT_STRING); + encoder.end_sequence(); + + SecureVector der = encoder.get_contents(); + if(encoding == PEM) + out.write(PEM_Code::encode(der, PEM_label_pref)); + else + out.write(der); + } + +/************************************************* +* Return a BER encoded X.509 object * +*************************************************/ +SecureVector X509_Object::BER_encode() const + { + Pipe ber; + ber.start_msg(); + encode(ber, RAW_BER); + ber.end_msg(); + return ber.read_all(); + } + +/************************************************* +* Return a PEM encoded X.509 object * +*************************************************/ +std::string X509_Object::PEM_encode() const + { + Pipe pem; + pem.start_msg(); + encode(pem, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/************************************************* +* Return the TBS data * +*************************************************/ +SecureVector X509_Object::tbs_data() const + { + return DER::put_in_sequence(tbs_bits); + } + +/************************************************* +* Return the signature of this object * +*************************************************/ +SecureVector X509_Object::signature() const + { + return sig; + } + +/************************************************* +* Return the algorithm used to sign this object * +*************************************************/ +AlgorithmIdentifier X509_Object::signature_algorithm() const + { + return sig_algo; + } + +/************************************************* +* Try to decode the actual information * +*************************************************/ +void X509_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.substr(23, std::string::npos) + ")"); + } + catch(Invalid_Argument& e) + { + const std::string what = e.what(); + throw Decoding_Error(PEM_label_pref + " decoding failed (" + + what.substr(7, std::string::npos) + ")"); + } + } + +} --- botan/x509_obj.h +++ botan/x509_obj.h @@ -0,0 +1,47 @@ +/************************************************* +* X.509 SIGNED Object Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_OBJECT_H__ +#define BOTAN_X509_OBJECT_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Generic X.509 SIGNED Object * +*************************************************/ +class X509_Object + { + public: + SecureVector tbs_data() const; + SecureVector signature() const; + AlgorithmIdentifier signature_algorithm() const; + + void encode(Pipe&, X509_Encoding = PEM) const; + SecureVector BER_encode() const; + std::string PEM_encode() const; + + X509_Object(DataSource&, const std::string&); + X509_Object(const std::string&, const std::string&); + virtual ~X509_Object() {} + protected: + void do_decode(); + X509_Object() {} + AlgorithmIdentifier sig_algo; + SecureVector tbs_bits, sig; + private: + virtual void force_decode() = 0; + void init(DataSource&, const std::string&); + void decode_info(DataSource&); + std::vector PEM_labels_allowed; + std::string PEM_label_pref; + }; + +} + +#endif --- botan/x509cert.cpp +++ botan/x509cert.cpp @@ -0,0 +1,442 @@ +/************************************************* +* X.509 Certificates Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Get information from the DistinguishedName * +*************************************************/ +void load_info(std::multimap& names, + const X509_DN& dn_info) + { + typedef std::multimap::const_iterator rdn_iter; + std::multimap attr = dn_info.get_attributes(); + + for(rdn_iter j = attr.begin(); j != attr.end(); j++) + { + const std::string oid_name = OIDS::lookup(j->first); + + if(oid_name == "PKCS9.EmailAddress") + multimap_insert(names, std::string("RFC822"), j->second); + else + multimap_insert(names, oid_name, j->second); + } + } + +/************************************************* +* Get information from the alternative name * +*************************************************/ +void load_info(std::multimap& names, + const AlternativeName& alt_info) + { + typedef std::multimap::const_iterator rdn_iter; + std::multimap attr = alt_info.get_attributes(); + + for(rdn_iter j = attr.begin(); j != attr.end(); j++) + multimap_insert(names, j->first, j->second); + } + +/************************************************* +* Get some information from names * +*************************************************/ +std::string get_info(const std::multimap& names, + const std::string& info) + { + typedef std::multimap::const_iterator rdn_iter; + + const std::string what = X509_DN::deref_info_field(info); + std::pair range = names.equal_range(what); + + std::string value; + for(rdn_iter j = range.first; j != range.second; j++) + value += j->second + '/'; + if(value.size()) + value.erase(value.size() - 1, 1); + return value; + } + +/************************************************* +* Create and populate a X509_DN * +*************************************************/ +X509_DN create_dn(const std::multimap& names) + { + typedef std::multimap::const_iterator rdn_iter; + + X509_DN new_dn; + for(rdn_iter j = names.begin(); j != names.end(); j++) + { + const std::string oid = j->first; + const std::string value = j->second; + if(!OIDS::have_oid(oid)) + continue; + new_dn.add_attribute(oid, j->second); + } + return new_dn; + } + +} + +/************************************************* +* X509_Certificate Constructor * +*************************************************/ +X509_Certificate::X509_Certificate(DataSource& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + is_ca = false; + version = max_path_len = 0; + constraints_value = NO_CONSTRAINTS; + do_decode(); + } + +/************************************************* +* X509_Certificate Constructor * +*************************************************/ +X509_Certificate::X509_Certificate(const std::string& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + is_ca = false; + version = max_path_len = 0; + constraints_value = NO_CONSTRAINTS; + do_decode(); + } + +/************************************************* +* Decode the TBSCertificate data * +*************************************************/ +void X509_Certificate::force_decode() + { + BER_Decoder tbs_cert(tbs_bits); + + BER::decode_optional(tbs_cert, version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + + if(version > 2) + throw Decoding_Error("Unknown X.509 cert version " + to_string(version)); + if(version < 2) + { + is_ca = Config::get_bool("x509/v1_assume_ca"); + max_path_len = NO_CERT_PATH_LIMIT; + } + + BER::decode(tbs_cert, serial); + + AlgorithmIdentifier sig_algo_inner; + BER::decode(tbs_cert, sig_algo_inner); + + if(sig_algo != sig_algo_inner) + throw Decoding_Error("Algorithm identifier mismatch"); + + X509_DN dn_issuer; + BER::decode(tbs_cert, dn_issuer); + load_info(issuer, dn_issuer); + + BER_Decoder validity = BER::get_subsequence(tbs_cert); + BER::decode(validity, start); + BER::decode(validity, end); + validity.verify_end(); + + X509_DN dn_subject; + BER::decode(tbs_cert, dn_subject); + load_info(subject, dn_subject); + + 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); + pub_key = DER::put_in_sequence(public_key.value); + + BER::decode_optional_string(tbs_cert, v2_issuer_key_id, BIT_STRING, + ASN1_Tag(1), CONTEXT_SPECIFIC); + BER::decode_optional_string(tbs_cert, v2_subject_key_id, BIT_STRING, + ASN1_Tag(2), CONTEXT_SPECIFIC); + + 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)) + { + BER_Decoder v3_exts_decoder(v3_exts_data.value); + BER_Decoder sequence = BER::get_subsequence(v3_exts_decoder); + + while(sequence.more_items()) + { + Extension extn; + BER::decode(sequence, extn); + handle_v3_extension(extn); + } + sequence.verify_end(); + v3_exts_decoder.verify_end(); + } + 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"); + } + +/************************************************* +* Decode a particular v3 extension * +*************************************************/ +void X509_Certificate::handle_v3_extension(const Extension& extn) + { + BER_Decoder value(extn.value); + + if(extn.oid == OIDS::lookup("X509v3.KeyUsage")) + BER::decode(value, constraints_value); + else if(extn.oid == OIDS::lookup("X509v3.ExtendedKeyUsage")) + { + BER_Decoder key_usage = BER::get_subsequence(value); + while(key_usage.more_items()) + { + OID usage_oid; + BER::decode(key_usage, usage_oid); + ex_constraints_list.push_back(usage_oid); + } + std::sort(ex_constraints_list.begin(), ex_constraints_list.end()); + } + else if(extn.oid == OIDS::lookup("X509v3.BasicConstraints")) + { + BER_Decoder basic_constraints = BER::get_subsequence(value); + BER::decode_optional(basic_constraints, is_ca, + BOOLEAN, UNIVERSAL, false); + BER::decode_optional(basic_constraints, max_path_len, + INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT); + } + else if(extn.oid == OIDS::lookup("X509v3.SubjectKeyIdentifier")) + BER::decode(value, v3_subject_key_id, OCTET_STRING); + else if(extn.oid == OIDS::lookup("X509v3.AuthorityKeyIdentifier")) + { + BER_Decoder key_id = BER::get_subsequence(value); + BER::decode_optional_string(key_id, v3_issuer_key_id, OCTET_STRING, + ASN1_Tag(0), CONTEXT_SPECIFIC); + } + else if(extn.oid == OIDS::lookup("X509v3.SubjectAlternativeName")) + { + AlternativeName alt_name; + BER::decode(value, alt_name); + load_info(subject, alt_name); + } + else if(extn.oid == OIDS::lookup("X509v3.IssuerAlternativeName")) + { + AlternativeName alt_name; + BER::decode(value, alt_name); + load_info(issuer, alt_name); + } + else if(extn.oid == OIDS::lookup("X509v3.CertificatePolicies")) + { + BER_Decoder ber_policies = BER::get_subsequence(value); + while(ber_policies.more_items()) + { + OID oid; + BER_Decoder policy = BER::get_subsequence(ber_policies); + BER::decode(policy, oid); + + if(extn.critical && policy.more_items()) + throw Decoding_Error("X.509 v3 critical policy has qualifiers"); + + policies_list.push_back(oid); + } + } + else + { + if(extn.critical) + throw Decoding_Error("Unknown critical X.509 v3 extension: " + + extn.oid.as_string()); + return; + } + + value.verify_end(); + } + +/************************************************* +* Return the X.509 version in use * +*************************************************/ +u32bit X509_Certificate::x509_version() const + { + return (version + 1); + } + +/************************************************* +* Return the time this cert becomes valid * +*************************************************/ +std::string X509_Certificate::start_time() const + { + return start.readable_string(); + } + +/************************************************* +* Return the time this cert becomes invalid * +*************************************************/ +std::string X509_Certificate::end_time() const + { + return end.readable_string(); + } + +/************************************************* +* Return information about the subject * +*************************************************/ +std::string X509_Certificate::subject_info(const std::string& info) const + { + return get_info(subject, info); + } + +/************************************************* +* Return information about the issuer * +*************************************************/ +std::string X509_Certificate::issuer_info(const std::string& info) const + { + return get_info(issuer, info); + } + +/************************************************* +* Return the public key in this certificate * +*************************************************/ +X509_PublicKey* X509_Certificate::subject_public_key() const + { + return X509::load_key(pub_key); + } + +/************************************************* +* Check if the certificate is self-signed * +*************************************************/ +bool X509_Certificate::self_signed() const + { + return (create_dn(issuer) == create_dn(subject)); + } + +/************************************************* +* Check if the certificate has a SKID * +*************************************************/ +bool X509_Certificate::has_SKID() const + { + if(v3_subject_key_id.has_items()) + return true; + return false; + } + +/************************************************* +* Check if the certificate is for a CA * +*************************************************/ +bool X509_Certificate::is_CA_cert() const + { + if(!is_ca) return false; + if((constraints_value & KEY_CERT_SIGN) || + (constraints_value == NO_CONSTRAINTS)) + return true; + return false; + } + +/************************************************* +* Return the path length constraint * +*************************************************/ +u32bit X509_Certificate::path_limit() const + { + return max_path_len; + } + +/************************************************* +* Return the key usage constraints * +*************************************************/ +Key_Constraints X509_Certificate::constraints() const + { + return constraints_value; + } + +/************************************************* +* Return the list of extended key usage OIDs * +*************************************************/ +std::vector X509_Certificate::ex_constraints() const + { + return ex_constraints_list; + } + +/************************************************* +* Return the list of certificate policies * +*************************************************/ +std::vector X509_Certificate::policies() const + { + return policies_list; + } + +/************************************************* +* Return the authority key id * +*************************************************/ +MemoryVector X509_Certificate::authority_key_id() const + { + return v3_issuer_key_id; + } + +/************************************************* +* Return the subject key id * +*************************************************/ +MemoryVector X509_Certificate::subject_key_id() const + { + return v3_subject_key_id; + } + +/************************************************* +* Return the certificate serial number * +*************************************************/ +MemoryVector X509_Certificate::serial_number() const + { + return BigInt::encode(serial); + } + +/************************************************* +* Return the certificate serial number * +*************************************************/ +BigInt X509_Certificate::serial_number_bn() const + { + return serial; + } + +/************************************************* +* Return the distinguished name of the issuer * +*************************************************/ +X509_DN X509_Certificate::issuer_dn() const + { + return create_dn(issuer); + } + +/************************************************* +* Return the distinguished name of the subject * +*************************************************/ +X509_DN X509_Certificate::subject_dn() const + { + return create_dn(subject); + } + +/************************************************* +* Compare two certificates for equality * +*************************************************/ +bool X509_Certificate::operator==(const X509_Certificate& cert) const + { + if(sig != cert.sig || pub_key != cert.pub_key || sig_algo != cert.sig_algo) + return false; + if(issuer != cert.issuer || subject != cert.subject) + return false; + if(serial != cert.serial || version != cert.version) + return false; + if(start != cert.start || end != cert.end) + return false; + return true; + } + +/************************************************* +* X.509 Certificate Comparison * +*************************************************/ +bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2) + { + return !(cert1 == cert2); + } + +} --- botan/x509cert.h +++ botan/x509cert.h @@ -0,0 +1,79 @@ +/************************************************* +* X.509 Certificates Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_CERTS_H__ +#define BOTAN_X509_CERTS_H__ + +#include +#include +#include +#include + +namespace Botan { + +static const u32bit NO_CERT_PATH_LIMIT = 0xFFFFFFFF; + +/************************************************* +* X.509 Certificate * +*************************************************/ +class X509_Certificate : public X509_Object + { + public: + u32bit x509_version() const; + + std::string start_time() const; + std::string end_time() const; + + std::string subject_info(const std::string&) const; + std::string issuer_info(const std::string&) const; + X509_DN issuer_dn() const; + X509_DN subject_dn() const; + + MemoryVector serial_number() const; + BigInt serial_number_bn() const; + X509_PublicKey* subject_public_key() const; + bool self_signed() const; + bool has_SKID() const; + + bool is_CA_cert() const; + u32bit path_limit() const; + Key_Constraints constraints() const; + std::vector ex_constraints() const; + std::vector policies() const; + + MemoryVector authority_key_id() const; + MemoryVector subject_key_id() const; + + bool operator==(const X509_Certificate&) const; + + void force_decode(); + + X509_Certificate(DataSource&); + X509_Certificate(const std::string&); + private: + friend class X509_CA; + X509_Certificate() {} + void handle_v3_extension(const Extension&); + + std::multimap subject, issuer; + MemoryVector v3_issuer_key_id, v3_subject_key_id; + MemoryVector v2_issuer_key_id, v2_subject_key_id; + MemoryVector pub_key; + std::vector ex_constraints_list, policies_list; + BigInt serial; + X509_Time start, end; + Key_Constraints constraints_value; + u32bit version, max_path_len; + bool is_ca; + }; + +/************************************************* +* X.509 Certificate Comparison * +*************************************************/ +bool operator!=(const X509_Certificate&, const X509_Certificate&); + +} + +#endif --- botan/x509find.cpp +++ botan/x509find.cpp @@ -0,0 +1,187 @@ +/************************************************* +* X.509 Certificate Store Searching Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include + +namespace Botan { + +namespace X509_Store_Search { + +namespace { + +/************************************************* +* Comparison Function Pointer * +*************************************************/ +typedef bool (*compare_fn)(const std::string&, const std::string&); + +/************************************************* +* Predicate for caseless searching * +*************************************************/ +bool caseless_cmp(char a, char b) + { + return (to_lower(a) == to_lower(b)); + } + +/************************************************* +* Compare based on case-insensive substrings * +*************************************************/ +bool substring_match(const std::string& searching_for, + const std::string& found) + { + if(std::search(found.begin(), found.end(), searching_for.begin(), + searching_for.end(), caseless_cmp) != found.end()) + return true; + return false; + } + +/************************************************* +* Compare based on case-insensive match * +*************************************************/ +bool ignore_case(const std::string& searching_for, const std::string& found) + { + if(searching_for.size() != found.size()) + return false; + + return std::equal(found.begin(), found.end(), + searching_for.begin(), caseless_cmp); + } + +/************************************************* +* Search based on the contents of a DN entry * +*************************************************/ +class DN_Check : public X509_Store::Search_Func + { + public: + bool match(const X509_Certificate& cert) const + { + return compare(looking_for, cert.subject_info(dn_entry)); + } + + DN_Check(const std::string& entry, const std::string& target, + compare_fn func) : + compare(func), dn_entry(entry), looking_for(target) {} + private: + compare_fn compare; + const std::string dn_entry; + const std::string looking_for; + }; + +/************************************************* +* Search based on the key id * +*************************************************/ +class KeyID_Match : public X509_Store::Search_Func + { + public: + bool match(const X509_Certificate& cert) const + { + std::auto_ptr key(cert.subject_public_key()); + return (key->key_id() == key_id); + } + KeyID_Match(u64bit id) : key_id(id) {} + private: + u64bit key_id; + }; + +/************************************************* +* Search based on the issuer and serial number * +*************************************************/ +class IandS_Match : public X509_Store::Search_Func + { + public: + bool match(const X509_Certificate& cert) const + { + if(cert.serial_number() != serial) + return false; + return (cert.issuer_dn() == issuer); + } + IandS_Match(const X509_DN& i, const MemoryRegion& s) : + issuer(i), serial(s) {} + private: + X509_DN issuer; + MemoryVector serial; + }; + +/************************************************* +* Search based on the subject key id * +*************************************************/ +class SKID_Match : public X509_Store::Search_Func + { + public: + bool match(const X509_Certificate& cert) const + { + return (cert.subject_key_id() == skid); + } + SKID_Match(const MemoryRegion& s) : skid(s) {} + private: + MemoryVector skid; + }; + +} + +/************************************************* +* Search for a certificate by email address * +*************************************************/ +std::vector by_email(const X509_Store& store, + const std::string& email) + { + DN_Check search_params("RFC822", email, ignore_case); + return store.get_certs(search_params); + } + +/************************************************* +* Search for a certificate by CommonName * +*************************************************/ +std::vector by_name(const X509_Store& store, + const std::string& name) + { + DN_Check search_params("CommonName", name, substring_match); + return store.get_certs(search_params); + } + +/************************************************* +* Search for a certificate by DNS name * +*************************************************/ +std::vector by_dns(const X509_Store& store, + const std::string& dns) + { + DN_Check search_params("DNS", dns, ignore_case); + return store.get_certs(search_params); + } + +/************************************************* +* Search for a certificate by key id * +*************************************************/ +std::vector by_keyid(const X509_Store& store, u64bit key_id) + { + KeyID_Match search_params(key_id); + return store.get_certs(search_params); + } + +/************************************************* +* Search for a certificate by issuer/serial * +*************************************************/ +std::vector by_iands(const X509_Store& store, + const X509_DN& issuer, + const MemoryRegion& serial) + { + IandS_Match search_params(issuer, serial); + return store.get_certs(search_params); + } + +/************************************************* +* Search for a certificate by subject keyid * +*************************************************/ +std::vector by_SKID(const X509_Store& store, + const MemoryRegion& skid) + { + SKID_Match search_params(skid); + return store.get_certs(search_params); + } + +} + +} --- botan/x509opt.cpp +++ botan/x509opt.cpp @@ -0,0 +1,107 @@ +/************************************************* +* X.509 Certificate Options Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#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(u32bit 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) + { + const u32bit DEFAULT_EXPIRE = Config::get_time("x509/ca/default_expire"); + const u32bit OFFSET_FROM_NOW = Config::get_time("x509/ca/signing_offset"); + + is_CA = false; + path_limit = 0; + constraints = NO_CONSTRAINTS; + + const u64bit current_time = system_time(); + + start = X509_Time(current_time - OFFSET_FROM_NOW); + end = X509_Time(current_time - OFFSET_FROM_NOW + DEFAULT_EXPIRE); + + 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]; + } + +} --- botan/x509self.cpp +++ botan/x509self.cpp @@ -0,0 +1,233 @@ +/************************************************* +* X.509 Certificate Authority Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Shared setup for self-signed items * +*************************************************/ +MemoryVector shared_setup(const X509_Cert_Options& opts, + const PKCS8_PrivateKey& key) + { + const PKCS8_PrivateKey* key_pointer = &key; + if(!dynamic_cast(key_pointer)) + throw Invalid_Argument("Key type " + key.algo_name() + " cannot sign"); + + opts.sanity_check(); + + Pipe key_encoder; + key_encoder.start_msg(); + X509::encode(key, key_encoder, RAW_BER); + key_encoder.end_msg(); + + return key_encoder.read_all(); + } + +/************************************************* +* 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); + } + +/************************************************* +* Choose a signing format for the key * +*************************************************/ +PK_Signer* choose_sig_format(const PKCS8_PrivateKey& key, + AlgorithmIdentifier& sig_algo) + { + std::string padding; + Signature_Format format; + Config::choose_sig_format(key.algo_name(), padding, format); + + sig_algo.oid = OIDS::lookup(key.algo_name() + "/" + padding); + sig_algo.parameters = key.DER_encode_params(); + + const PK_Signing_Key& sig_key = dynamic_cast(key); + + return get_pk_signer(sig_key, padding, format); + } + +/************************************************* +* Encode an attribute for PKCS #10 request * +*************************************************/ +void do_attribute(DER_Encoder& tbs_req, DER_Encoder& attr_bits, + const std::string& oid_str) + { + Attribute attr(OIDS::lookup(oid_str), attr_bits.get_contents()); + DER::encode(tbs_req, attr); + } + +/************************************************* +* Encode an Extension for a PKCS #10 request * +*************************************************/ +void do_ext(DER_Encoder& attr_encoder, DER_Encoder& extn_bits, + const std::string& oid) + { + Extension extn(oid, extn_bits.get_contents()); + DER::encode(attr_encoder, extn); + } + +/************************************************* +* Encode X.509 extensions for a PKCS #10 request * +*************************************************/ +void encode_extensions(DER_Encoder& attr_encoder, + const AlternativeName& subject_alt, + bool is_CA, u32bit path_limit, + Key_Constraints constraints, + const std::vector& ex_constraints) + { + DER_Encoder v3_ext; + + attr_encoder.start_sequence(); + if(is_CA) + { + v3_ext.start_sequence(); + DER::encode(v3_ext, true); + if(path_limit != NO_CERT_PATH_LIMIT) + DER::encode(v3_ext, path_limit); + v3_ext.end_sequence(); + do_ext(attr_encoder, v3_ext, "X509v3.BasicConstraints"); + } + + if(subject_alt.has_items()) + { + DER::encode(v3_ext, subject_alt); + do_ext(attr_encoder, v3_ext, "X509v3.SubjectAlternativeName"); + } + + if(constraints != NO_CONSTRAINTS) + { + DER::encode(v3_ext, constraints); + do_ext(attr_encoder, v3_ext, "X509v3.KeyUsage"); + } + + if(ex_constraints.size()) + { + v3_ext.start_sequence(); + for(u32bit j = 0; j != ex_constraints.size(); j++) + DER::encode(v3_ext, ex_constraints[j]); + v3_ext.end_sequence(); + do_ext(attr_encoder, v3_ext, "X509v3.ExtendedKeyUsage"); + } + attr_encoder.end_sequence(); + } + +} + +namespace X509 { + +/************************************************* +* Create a new self-signed X.509 certificate * +*************************************************/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, + const PKCS8_PrivateKey& key) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + MemoryVector pub_key = shared_setup(opts, key); + std::auto_ptr signer(choose_sig_format(key, 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); + + return X509_CA::make_cert(signer.get(), sig_algo, pub_key, + MemoryVector(), opts.start, opts.end, + subject_dn, subject_dn, + opts.is_CA, opts.path_limit, + subject_alt, constraints, opts.ex_constraints); + } + +/************************************************* +* Create a PKCS #10 certificate request * +*************************************************/ +PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const PKCS8_PrivateKey& key) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + MemoryVector pub_key = shared_setup(opts, key); + std::auto_ptr signer(choose_sig_format(key, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + const u32bit PKCS10_VERSION = 0; + + DER_Encoder tbs_req; + + tbs_req.start_sequence(); + DER::encode(tbs_req, PKCS10_VERSION); + DER::encode(tbs_req, subject_dn); + tbs_req.add_raw_octets(pub_key); + + tbs_req.start_explicit(ASN1_Tag(0)); + + DER_Encoder attr_encoder; + + if(opts.challenge != "") + { + ASN1_String challenge(opts.challenge, DIRECTORY_STRING); + DER::encode(attr_encoder, challenge); + do_attribute(tbs_req, attr_encoder, "PKCS9.ChallengePassword"); + } + + Key_Constraints constraints; + if(opts.is_CA) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + constraints = find_constraints(key, opts.constraints); + + encode_extensions(attr_encoder, subject_alt, opts.is_CA, opts.path_limit, + constraints, opts.ex_constraints); + do_attribute(tbs_req, attr_encoder, "PKCS9.ExtensionRequest"); + + tbs_req.end_explicit(ASN1_Tag(0)); + + tbs_req.end_sequence(); + + MemoryVector tbs_bits = tbs_req.get_contents(); + MemoryVector sig = signer->sign_message(tbs_bits); + + DER_Encoder full_req; + full_req.start_sequence(); + full_req.add_raw_octets(tbs_bits); + DER::encode(full_req, sig_algo); + DER::encode(full_req, sig, BIT_STRING); + full_req.end_sequence(); + + DataSource_Memory source(full_req.get_contents()); + + return PKCS10_Request(source); + } + +} + +} --- botan/x509self.h +++ botan/x509self.h @@ -0,0 +1,73 @@ +/************************************************* +* X.509 Self-Signed Certificate Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_SELF_H__ +#define BOTAN_X509_SELF_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* Options for X.509 Certificates * +*************************************************/ +class X509_Cert_Options + { + public: + std::string common_name; + std::string country; + std::string organization; + std::string org_unit; + std::string locality; + std::string state; + std::string serial_number; + + std::string email; + std::string uri; + std::string dns; + + std::string challenge; + + X509_Time start, end; + + bool is_CA; + u32bit path_limit; + Key_Constraints constraints; + std::vector ex_constraints; + + void sanity_check() const; + + void CA_key(u32bit = 8); + void not_before(const std::string&); + void not_after(const std::string&); + + void add_constraints(Key_Constraints); + void add_ex_constraint(const OID&); + void add_ex_constraint(const std::string&); + + X509_Cert_Options(const std::string& = ""); + }; + +namespace X509 { + +/************************************************* +* Create a self-signed X.509 certificate * +*************************************************/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options&, + const PKCS8_PrivateKey&); + +/************************************************* +* Create a PKCS #10 certificate request * +*************************************************/ +PKCS10_Request create_cert_req(const X509_Cert_Options&, + const PKCS8_PrivateKey&); + +} + +} + +#endif --- botan/x509stor.cpp +++ botan/x509stor.cpp @@ -0,0 +1,667 @@ +/************************************************* +* X.509 Certificate Store Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/************************************************* +* Compare the value of unique ID fields * +*************************************************/ +bool compare_ids(const MemoryVector& id1, + const MemoryVector& id2) + { + if(!id1.size() || !id2.size()) + return true; + return (id1 == id2); + } + +/************************************************* +* Check a particular usage restriction * +*************************************************/ +bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage, + X509_Store::Cert_Usage check_for, Key_Constraints constraints) + { + if((usage & check_for) == 0) + return true; + if(cert.constraints() == NO_CONSTRAINTS) + return true; + if(cert.constraints() & constraints) + return true; + return false; + } + +/************************************************* +* Check a particular usage restriction * +*************************************************/ +bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage, + X509_Store::Cert_Usage check_for, + const std::string& usage_oid) + { + if((usage & check_for) == 0) + return true; + + const std::vector constraints = cert.ex_constraints(); + + if(constraints.size() == 0) + return true; + + return std::binary_search(constraints.begin(), constraints.end(), + OIDS::lookup(usage_oid)); + } + +/************************************************* +* Check the usage restrictions * +*************************************************/ +X509_Code usage_check(const X509_Certificate& cert, + X509_Store::Cert_Usage usage) + { + if(usage == X509_Store::ANY) + return VERIFIED; + + if(!check_usage(cert, usage, X509_Store::CRL_SIGNING, CRL_SIGN)) + return CA_CERT_NOT_FOR_CRL_ISSUER; + + if(!check_usage(cert, usage, X509_Store::TLS_SERVER, "PKIX.ServerAuth")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::TLS_CLIENT, "PKIX.ClientAuth")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::CODE_SIGNING, "PKIX.CodeSigning")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::EMAIL_PROTECTION, + "PKIX.EmailProtection")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::TIME_STAMPING, + "PKIX.TimeStamping")) + return INVALID_USAGE; + + return VERIFIED; + } + +} + +/************************************************* +* Define equality for revocation data * +*************************************************/ +bool X509_Store::CRL_Data::operator==(const CRL_Data& other) const + { + if(issuer != other.issuer) + return false; + if(serial != other.serial) + return false; + return compare_ids(auth_key_id, other.auth_key_id); + } + +/************************************************* +* Define inequality for revocation data * +*************************************************/ +bool X509_Store::CRL_Data::operator!=(const CRL_Data& other) const + { + return !((*this) == other); + } + +/************************************************* +* Define an ordering for revocation data * +*************************************************/ +bool X509_Store::CRL_Data::operator<(const X509_Store::CRL_Data& other) const + { + if(*this == other) + return false; + + const MemoryVector& serial1 = serial; + const MemoryVector& key_id1 = auth_key_id; + const MemoryVector& serial2 = other.serial; + const MemoryVector& key_id2 = other.auth_key_id; + + if(compare_ids(key_id1, key_id2) == false) + { + if(std::lexicographical_compare(key_id1.begin(), key_id1.end(), + key_id2.begin(), key_id2.end())) + return true; + + if(std::lexicographical_compare(key_id2.begin(), key_id2.end(), + key_id1.begin(), key_id1.end())) + return false; + } + + if(compare_ids(serial1, serial2) == false) + { + if(std::lexicographical_compare(serial1.begin(), serial1.end(), + serial2.begin(), serial2.end())) + return true; + + if(std::lexicographical_compare(serial2.begin(), serial2.end(), + serial1.begin(), serial1.end())) + return false; + } + + return (issuer < other.issuer); + } + +/************************************************* +* X509_Store Constructor * +*************************************************/ +X509_Store::X509_Store() + { + revoked_info_valid = true; + } + +/************************************************* +* X509_Store Copy Constructor * +*************************************************/ +X509_Store::X509_Store(const X509_Store& store) + { + certs = store.certs; + revoked = store.revoked; + revoked_info_valid = store.revoked_info_valid; + for(u32bit j = 0; j != store.stores.size(); j++) + stores[j] = store.stores[j]->clone(); + } + +/************************************************* +* X509_Store Destructor * +*************************************************/ +X509_Store::~X509_Store() + { + for(u32bit j = 0; j != stores.size(); j++) + delete stores[j]; + } + +/************************************************* +* Verify a certificate's authenticity * +*************************************************/ +X509_Code X509_Store::validate_cert(const X509_Certificate& cert, + Cert_Usage cert_usage) + { + recompute_revoked_info(); + + std::vector indexes; + X509_Code chaining_result = construct_cert_chain(cert, indexes); + if(chaining_result != VERIFIED) + return chaining_result; + + const u64bit current_time = system_time(); + + s32bit time_check = validity_check(cert.start_time(), cert.end_time(), + current_time); + if(time_check < 0) return CERT_NOT_YET_VALID; + else if(time_check > 0) return CERT_HAS_EXPIRED; + + X509_Code sig_check_result = check_sig(cert, certs[indexes[0]]); + if(sig_check_result != VERIFIED) + return sig_check_result; + + if(is_revoked(cert)) + return CERT_IS_REVOKED; + + for(u32bit j = 0; j != indexes.size() - 1; j++) + { + const X509_Certificate& current_cert = certs[indexes[j]].cert; + time_check = validity_check(current_cert.start_time(), + current_cert.end_time(), current_time); + if(time_check < 0) return CERT_NOT_YET_VALID; + else if(time_check > 0) return CERT_HAS_EXPIRED; + + sig_check_result = check_sig(certs[indexes[j]], certs[indexes[j+1]]); + if(sig_check_result != VERIFIED) + return sig_check_result; + } + + return usage_check(cert, cert_usage); + } + +/************************************************* +* Find this certificate * +*************************************************/ +u32bit X509_Store::find_cert(const X509_DN& subject_dn, + const MemoryRegion& subject_key_id) const + { + for(u32bit j = 0; j != certs.size(); j++) + { + const X509_Certificate& this_cert = certs[j].cert; + if(compare_ids(this_cert.subject_key_id(), subject_key_id) && + this_cert.subject_dn() == subject_dn) + return j; + } + return NO_CERT_FOUND; + } + +/************************************************* +* Find the parent of this certificate * +*************************************************/ +u32bit X509_Store::find_parent_of(const X509_Certificate& cert) + { + const X509_DN issuer_dn = cert.issuer_dn(); + const MemoryVector auth_key_id = cert.authority_key_id(); + + u32bit index = find_cert(issuer_dn, auth_key_id); + + if(index != NO_CERT_FOUND) + return index; + + if(auth_key_id.size()) + { + for(u32bit j = 0; j != stores.size(); j++) + { + std::vector got = stores[j]->by_SKID(auth_key_id); + + if(got.size() == 0) continue; + + for(u32bit j = 0; j != got.size(); j++) + add_cert(got[j]); + return find_cert(issuer_dn, auth_key_id); + } + } + + return NO_CERT_FOUND; + } + +/************************************************* +* Construct a chain of certificate relationships * +*************************************************/ +X509_Code X509_Store::construct_cert_chain(const X509_Certificate& end_cert, + std::vector& indexes, + bool need_full_chain) + { + u32bit parent = find_parent_of(end_cert); + + while(true) + { + if(parent == NO_CERT_FOUND) + return CERT_ISSUER_NOT_FOUND; + indexes.push_back(parent); + + if(certs[parent].is_verified()) + if(certs[parent].verify_result() != VERIFIED) + return certs[parent].verify_result(); + + const X509_Certificate& parent_cert = certs[parent].cert; + if(!parent_cert.is_CA_cert()) + return CA_CERT_NOT_FOR_CERT_ISSUER; + + if(certs[parent].is_trusted()) + break; + if(parent_cert.self_signed()) + return CANNOT_ESTABLISH_TRUST; + + if(parent_cert.path_limit() < indexes.size() - 1) + return CERT_CHAIN_TOO_LONG; + + parent = find_parent_of(parent_cert); + } + + if(need_full_chain) + return VERIFIED; + + while(true) + { + if(indexes.size() < 2) + break; + + const u32bit cert = indexes.back(); + + if(certs[cert].is_verified()) + { + if(certs[cert].verify_result() != VERIFIED) + throw Internal_Error("X509_Store::construct_cert_chain"); + indexes.pop_back(); + } + else + break; + } + + const u32bit last_cert = indexes.back(); + const u32bit parent_of_last_cert = find_parent_of(certs[last_cert].cert); + if(parent_of_last_cert == NO_CERT_FOUND) + return CERT_ISSUER_NOT_FOUND; + indexes.push_back(parent_of_last_cert); + + return VERIFIED; + } + +/************************************************* +* Check the CAs signature on a certificate * +*************************************************/ +X509_Code X509_Store::check_sig(const Cert_Info& cert_info, + const Cert_Info& ca_cert_info) const + { + if(cert_info.is_verified()) + return cert_info.verify_result(); + + const X509_Certificate& cert = cert_info.cert; + const X509_Certificate& ca_cert = ca_cert_info.cert; + + X509_Code verify_code = check_sig(cert, ca_cert.subject_public_key()); + + cert_info.set_result(verify_code); + + return verify_code; + } + +/************************************************* +* Check a CA's signature * +*************************************************/ +X509_Code X509_Store::check_sig(const X509_Object& object, X509_PublicKey* key) + { + std::auto_ptr pub_key(key); + std::auto_ptr verifier; + + try { + std::vector sig_info = + split_on(OIDS::lookup(object.signature_algorithm().oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + return SIGNATURE_ERROR; + + std::string padding = sig_info[1]; + Signature_Format format; + if(key->message_parts() >= 2) format = DER_SEQUENCE; + else format = IEEE_1363; + + if(dynamic_cast(pub_key.get())) + { + PK_Verifying_with_MR_Key* sig_key = + dynamic_cast(pub_key.get()); + verifier.reset(get_pk_verifier(*sig_key, padding, format)); + } + else if(dynamic_cast(pub_key.get())) + { + PK_Verifying_wo_MR_Key* sig_key = + dynamic_cast(pub_key.get()); + verifier.reset(get_pk_verifier(*sig_key, padding, format)); + } + else + return CA_CERT_CANNOT_SIGN; + + bool valid = verifier->verify_message(object.tbs_data(), + object.signature()); + + if(valid) + return VERIFIED; + else + return SIGNATURE_ERROR; + } + catch(Decoding_Error) { return CERT_FORMAT_ERROR; } + catch(Exception) {} + + return UNKNOWN_X509_ERROR; + } + +/************************************************* +* Recompute the revocation status of the certs * +*************************************************/ +void X509_Store::recompute_revoked_info() const + { + if(revoked_info_valid) + return; + + for(u32bit j = 0; j != certs.size(); j++) + { + if((certs[j].is_verified()) && (certs[j].verify_result() != VERIFIED)) + continue; + + if(is_revoked(certs[j].cert)) + certs[j].set_result(CERT_IS_REVOKED); + } + + revoked_info_valid = true; + } + +/************************************************* +* Check if a certificate is revoked * +*************************************************/ +bool X509_Store::is_revoked(const X509_Certificate& cert) const + { + CRL_Data revoked_info; + revoked_info.issuer = cert.issuer_dn(); + revoked_info.serial = cert.serial_number(); + revoked_info.auth_key_id = cert.authority_key_id(); + + if(std::binary_search(revoked.begin(), revoked.end(), revoked_info)) + return true; + return false; + } + +/************************************************* +* Retrieve all the certificates in the store * +*************************************************/ +std::vector +X509_Store::get_certs(const Search_Func& search) const + { + std::vector found_certs; + for(u32bit j = 0; j != certs.size(); j++) + { + if(search.match(certs[j].cert)) + found_certs.push_back(certs[j].cert); + } + return found_certs; + } + +/************************************************* +* Construct a path back to a root for this cert * +*************************************************/ +std::vector +X509_Store::get_cert_chain(const X509_Certificate& cert) + { + std::vector result; + std::vector indexes; + X509_Code chaining_result = construct_cert_chain(cert, indexes, true); + + if(chaining_result != VERIFIED) + throw Invalid_State("X509_Store::get_cert_chain: Can't construct chain"); + + for(u32bit j = 0; j != indexes.size(); j++) + result.push_back(certs[indexes[j]].cert); + return result; + } + +/************************************************* +* Add a certificate store to the list of stores * +*************************************************/ +void X509_Store::add_new_certstore(Certificate_Store* certstore) + { + stores.push_back(certstore); + } + +/************************************************* +* Add a certificate to the store * +*************************************************/ +void X509_Store::add_cert(const X509_Certificate& cert, bool trusted) + { + if(trusted && !cert.self_signed()) + throw Invalid_Argument("X509_Store: Trusted certs must be self-signed"); + + if(find_cert(cert.subject_dn(), cert.subject_key_id()) == NO_CERT_FOUND) + { + revoked_info_valid = false; + Cert_Info info(cert, trusted); + certs.push_back(info); + } + else if(trusted) + { + for(u32bit j = 0; j != certs.size(); j++) + { + const X509_Certificate& this_cert = certs[j].cert; + if(this_cert == cert) + certs[j].trusted = trusted; + } + } + } + +/************************************************* +* Add one or more certificates to the store * +*************************************************/ +void X509_Store::do_add_certs(DataSource& source, bool trusted) + { + while(!source.end_of_data()) + { + try { + X509_Certificate cert(source); + add_cert(cert, trusted); + } + catch(Decoding_Error) {} + catch(Invalid_Argument) {} + } + } + +/************************************************* +* Add one or more certificates to the store * +*************************************************/ +void X509_Store::add_certs(DataSource& source) + { + do_add_certs(source, false); + } + +/************************************************* +* Add one or more certificates to the store * +*************************************************/ +void X509_Store::add_trusted_certs(DataSource& source) + { + do_add_certs(source, true); + } + +/************************************************* +* Add one or more certificates to the store * +*************************************************/ +X509_Code X509_Store::add_crl(const X509_CRL& crl) + { + s32bit time_check = validity_check(crl.this_update(), crl.next_update(), + system_time()); + if(time_check < 0) return CRL_NOT_YET_VALID; + else if(time_check > 0) return CRL_HAS_EXPIRED; + + u32bit cert_index = NO_CERT_FOUND; + + for(u32bit j = 0; j != certs.size(); j++) + { + const X509_Certificate& this_cert = certs[j].cert; + if(compare_ids(this_cert.subject_key_id(), crl.authority_key_id())) + { + if(this_cert.subject_dn() == crl.issuer_dn()) + cert_index = j; + } + } + + if(cert_index == NO_CERT_FOUND) + return CRL_ISSUER_NOT_FOUND; + + const X509_Certificate& ca_cert = certs[cert_index].cert; + + X509_Code verify_result = validate_cert(ca_cert, CRL_SIGNING); + if(verify_result != VERIFIED) + return verify_result; + + verify_result = check_sig(crl, ca_cert.subject_public_key()); + if(verify_result != VERIFIED) + return verify_result; + + std::vector revoked_certs = crl.get_revoked(); + + for(u32bit j = 0; j != revoked_certs.size(); j++) + { + CRL_Data revoked_info; + revoked_info.issuer = crl.issuer_dn(); + revoked_info.serial = revoked_certs[j].serial; + revoked_info.auth_key_id = crl.authority_key_id(); + + std::vector::iterator p = + std::find(revoked.begin(), revoked.end(), revoked_info); + + if(revoked_certs[j].reason == REMOVE_FROM_CRL) + { + if(p == revoked.end()) continue; + revoked.erase(p); + } + else + { + if(p != revoked.end()) continue; + revoked.push_back(revoked_info); + } + } + + std::sort(revoked.begin(), revoked.end()); + revoked_info_valid = false; + + return VERIFIED; + } + +/************************************************* +* PEM encode the set of certificates * +*************************************************/ +std::string X509_Store::PEM_encode() const + { + std::string cert_store; + for(u32bit j = 0; j != certs.size(); j++) + cert_store += certs[j].cert.PEM_encode(); + return cert_store; + } + +/************************************************* +* Create a Cert_Info structure * +*************************************************/ +X509_Store::Cert_Info::Cert_Info(const X509_Certificate& c, + bool t) : cert(c), trusted(t) + { + checked = false; + result = UNKNOWN_X509_ERROR; + last_checked = 0; + } + +/************************************************* +* Return the verification results * +*************************************************/ +X509_Code X509_Store::Cert_Info::verify_result() const + { + if(!checked) + throw Invalid_State("Cert_Info::verify_result() called; not checked"); + return result; + } + +/************************************************* +* Set the verification results * +*************************************************/ +void X509_Store::Cert_Info::set_result(X509_Code code) const + { + result = code; + last_checked = system_time(); + checked = true; + } + +/************************************************* +* Check if this certificate can be trusted * +*************************************************/ +bool X509_Store::Cert_Info::is_trusted() const + { + return trusted; + } + +/************************************************* +* Check if this certificate has been verified * +*************************************************/ +bool X509_Store::Cert_Info::is_verified() const + { + if(!checked) + return false; + if(result != VERIFIED && result != CERT_NOT_YET_VALID) + return true; + + const u32bit CACHE_TIME = Config::get_time("x509/cache_verify_results"); + const u64bit current_time = system_time(); + + if(current_time > last_checked + CACHE_TIME) + checked = false; + + return checked; + } + +} --- botan/x509stor.h +++ botan/x509stor.h @@ -0,0 +1,122 @@ +/************************************************* +* X.509 Certificate Store Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_X509_CERT_STORE_H__ +#define BOTAN_X509_CERT_STORE_H__ + +#include +#include +#include + +namespace Botan { + +/************************************************* +* X.509 Certificate Store * +*************************************************/ +class X509_Store + { + public: + class Search_Func + { + public: + virtual bool match(const X509_Certificate&) const = 0; + virtual ~Search_Func() {} + }; + + enum Cert_Usage { + ANY = 0x00, + TLS_SERVER = 0x01, + TLS_CLIENT = 0x02, + CODE_SIGNING = 0x04, + EMAIL_PROTECTION = 0x08, + TIME_STAMPING = 0x10, + CRL_SIGNING = 0x20 + }; + + X509_Code validate_cert(const X509_Certificate&, Cert_Usage = ANY); + + std::vector get_certs(const Search_Func&) const; + std::vector get_cert_chain(const X509_Certificate&); + std::string PEM_encode() const; + + X509_Code add_crl(const X509_CRL&); + void add_cert(const X509_Certificate&, bool = false); + void add_certs(DataSource&); + void add_trusted_certs(DataSource&); + + void add_new_certstore(Certificate_Store*); + + static X509_Code check_sig(const X509_Object&, X509_PublicKey*); + + X509_Store(); + X509_Store(const X509_Store&); + ~X509_Store(); + private: + X509_Store& operator=(const X509_Store&) { return (*this); } + + class Cert_Info + { + public: + bool is_verified() const; + bool is_trusted() const; + X509_Code verify_result() const; + void set_result(X509_Code) const; + Cert_Info(const X509_Certificate&, bool = false); + + X509_Certificate cert; + bool trusted; + private: + mutable bool checked; + mutable X509_Code result; + mutable u64bit last_checked; + }; + + class CRL_Data + { + public: + X509_DN issuer; + MemoryVector serial, auth_key_id; + bool operator==(const CRL_Data&) const; + bool operator!=(const CRL_Data&) const; + bool operator<(const CRL_Data&) const; + }; + + u32bit find_cert(const X509_DN&, const MemoryRegion&) const; + X509_Code check_sig(const Cert_Info&, const Cert_Info&) const; + void recompute_revoked_info() const; + + void do_add_certs(DataSource&, bool); + X509_Code construct_cert_chain(const X509_Certificate&, + std::vector&, bool = false); + + u32bit find_parent_of(const X509_Certificate&); + bool is_revoked(const X509_Certificate&) const; + + static const u32bit NO_CERT_FOUND = 0xFFFFFFFF; + std::vector certs; + std::vector revoked; + std::vector stores; + mutable bool revoked_info_valid; + }; + +namespace X509_Store_Search { + +/************************************************* +* Methods to search through a X509_Store * +*************************************************/ +std::vector by_email(const X509_Store&, const std::string&); +std::vector by_name(const X509_Store&, const std::string&); +std::vector by_dns(const X509_Store&, const std::string&); +std::vector by_keyid(const X509_Store&, u64bit); +std::vector by_iands(const X509_Store&, const X509_DN&, + const MemoryRegion&); +std::vector by_SKID(const X509_Store&, + const MemoryRegion&); + +} + +} + +#endif --- botan/x917_rng.cpp +++ botan/x917_rng.cpp @@ -0,0 +1,131 @@ +/************************************************* +* ANSI X9.17 RNG Source File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#include +#include + +namespace Botan { + +/************************************************* +* Generate a buffer of random bytes * +*************************************************/ +void ANSI_X917_RNG::randomize(byte out[], u32bit length) throw(PRNG_Unseeded) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + generate(system_clock()); + while(length >= output.size()) + { + xor_buf(out, output, output.size()); + length -= output.size(); + out += output.size(); + generate(system_clock()); + iteration++; + if(iteration == ITERATIONS_BEFORE_RESEED) + reseed(); + } + xor_buf(out, output, length); + generate(system_clock()); + } + +/************************************************* +* Refill the internal state * +*************************************************/ +void ANSI_X917_RNG::generate(u64bit input) throw() + { + SecureVector buffer(cipher->BLOCK_SIZE); + + xor_buf(tstamp, (const byte*)&input, sizeof(u64bit)); + cipher->encrypt(tstamp); + xor_buf(state, tstamp, cipher->BLOCK_SIZE); + cipher->encrypt(state, buffer); + xor_buf(state, buffer, tstamp, cipher->BLOCK_SIZE); + cipher->encrypt(state); + + for(u32bit j = 0; j != buffer.size(); j++) + output[j % output.size()] ^= buffer[j]; + } + +/************************************************* +* Reseed the internal state * +*************************************************/ +void ANSI_X917_RNG::reseed() throw() + { + SecureVector key(cipher->BLOCK_SIZE); + + generate(system_clock()); + for(u32bit j = 0; j != key.size(); j++) + key[j] = state[j]; + cipher->encrypt(key); + + cipher->set_key(key, key.size()); + generate(system_clock()); + iteration = 0; + } + +/************************************************* +* Add entropy to internal state * +*************************************************/ +void ANSI_X917_RNG::add_randomness(const byte data[], u32bit length) throw() + { + update_entropy(data, length, state.size()); + + while(length) + { + u32bit added = std::min(state.size(), length); + xor_buf(state, data, added); + generate(system_clock()); + length -= added; + data += added; + } + reseed(); + } + +/************************************************* +* Check if the the PRNG is seeded * +*************************************************/ +bool ANSI_X917_RNG::is_seeded() const + { + return (entropy >= 96); + } + +/************************************************* +* Clear memory of sensitive data * +*************************************************/ +void ANSI_X917_RNG::clear() throw() + { + cipher->clear(); + tstamp.clear(); + state.clear(); + output.clear(); + entropy = iteration = 0; + } + +/************************************************* +* Return the name of this type * +*************************************************/ +std::string ANSI_X917_RNG::name() const + { + return "X9.17(" + cipher->name() + ")"; + } + +/************************************************* +* ANSI X917 RNG Constructor * +*************************************************/ +ANSI_X917_RNG::ANSI_X917_RNG() : ITERATIONS_BEFORE_RESEED(16) + { + cipher = get_block_cipher("AES"); + output.create(cipher->BLOCK_SIZE / 2); + state.create(cipher->BLOCK_SIZE); + tstamp.create(cipher->BLOCK_SIZE); + entropy = iteration = 0; + + cipher->set_key(state, state.size()); + generate(system_clock()); + reseed(); + } + +} --- botan/x917_rng.h +++ botan/x917_rng.h @@ -0,0 +1,37 @@ +/************************************************* +* ANSI X9.17 RNG Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ANSI_X917_RNG_H__ +#define BOTAN_ANSI_X917_RNG_H__ + +#include + +namespace Botan { + +/************************************************* +* ANSI X9.17 RNG * +*************************************************/ +class ANSI_X917_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], u32bit) throw(PRNG_Unseeded); + bool is_seeded() const; + void clear() throw(); + std::string name() const; + ANSI_X917_RNG(); + ~ANSI_X917_RNG() { delete cipher; } + private: + void add_randomness(const byte[], u32bit) throw(); + void generate(u64bit) throw(); + void reseed() throw(); + const u32bit ITERATIONS_BEFORE_RESEED; + BlockCipher* cipher; + SecureVector output, state, tstamp; + u32bit iteration; + }; + +} + +#endif --- botan/x919_mac.h +++ botan/x919_mac.h @@ -0,0 +1,36 @@ +/************************************************* +* ANSI X9.19 MAC Header File * +* (C) 1999-2004 The Botan Project * +*************************************************/ + +#ifndef BOTAN_ANSI_X919_MAC_H__ +#define BOTAN_ANSI_X919_MAC_H__ + +#include + +namespace Botan { + +/************************************************* +* ANSI X9.19 MAC * +*************************************************/ +class ANSI_X919_MAC : public MessageAuthenticationCode + { + public: + void clear() throw(); + std::string name() const { return "X9.19-MAC"; } + MessageAuthenticationCode* clone() const { return new ANSI_X919_MAC; } + ANSI_X919_MAC(); + ~ANSI_X919_MAC(); + private: + void add_data(const byte[], u32bit); + void final_result(byte[]); + void key(const byte[], u32bit); + BlockCipher* e; + BlockCipher* d; + SecureBuffer state; + u32bit position; + }; + +} + +#endif --- cert.cc +++ cert.cc @@ -391,7 +391,7 @@ load_priv_key(app, t.key, priv); - make_signature(app.lua, t.key, priv, signed_text, t.sig); + make_signature(app, t.key, priv, signed_text, t.sig); } cert_status @@ -419,7 +419,7 @@ string signed_text; cert_signable_text(t, signed_text); - if (check_signature(app.lua, t.key, pub, signed_text, t.sig)) + if (check_signature(app, t.key, pub, signed_text, t.sig)) return cert_ok; else return cert_bad; --- configure.ac +++ configure.ac @@ -250,6 +250,7 @@ AC_SEARCH_LIBS([inet_aton], [resolv]) AC_SEARCH_LIBS([accept], [socket]) AC_SEARCH_LIBS([inet_ntoa], [nsl]) +AC_CHECK_LIB([z], [deflate], , AC_MSG_FAILURE([zlib is required])) ########## --- contrib/monotone-notify.pl +++ contrib/monotone-notify.pl @@ -279,6 +279,8 @@ my $message_count = 0; # It's nice with a little bit of statistics. + my $message_count = 0; # It's nice with a little bit of statistics. + foreach my $date (sort keys %timeline) { foreach my $revision (keys %{$timeline{$date}}) { foreach my $sendinfo (([ 1, "Notify.debug-diffs", $difflogs_to ], --- database_check.cc +++ database_check.cc @@ -314,7 +314,7 @@ { std::string signed_text; cert_signable_text(i->inner(), signed_text); - checked.good_sig = check_signature(app.lua, i->inner().key, + checked.good_sig = check_signature(app, i->inner().key, checked_keys[i->inner().key].pub_encoded, signed_text, i->inner().sig); } --- file_io.cc +++ file_io.cc @@ -1,16 +1,17 @@ // copyright (C) 2002, 2003 graydon hoare // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) // see the file COPYING for details #include // for rename(2) +#include +#include #include #include #include -#include "cryptopp/filters.h" -#include "cryptopp/files.h" +#include "botan/botan.h" #include "file_io.hh" #include "lua.hh" @@ -377,11 +378,13 @@ ifstream file(p.string().c_str(), ios_base::in | ios_base::binary); - string in; if (!file) throw oops(string("cannot open file ") + p.string() + " for reading"); - CryptoPP::FileSource f(file, true, new CryptoPP::StringSink(in)); - dat = in; + Botan::Pipe pipe; + pipe.start_msg(); + file >> pipe; + pipe.end_msg(); + dat = pipe.read_all_as_string(); } // This function can only be called once per run. @@ -391,9 +394,11 @@ static bool have_consumed_stdin = false; N(!have_consumed_stdin, F("Cannot read standard input multiple times")); have_consumed_stdin = true; - string in; - CryptoPP::FileSource f(cin, true, new CryptoPP::StringSink(in)); - dat = in; + Botan::Pipe pipe; + pipe.start_msg(); + cin >> pipe; + pipe.end_msg(); + dat = pipe.read_all_as_string(); } void @@ -505,7 +510,8 @@ ios_base::out | ios_base::trunc | ios_base::binary); if (!file) throw oops(string("cannot open file ") + tmp.string() + " for writing"); - CryptoPP::StringSource s(dat(), true, new CryptoPP::FileSink(file)); + Botan::Pipe pipe(new Botan::DataSink_Stream(file)); + pipe.process_msg(dat()); // data.tmp closes } --- fsck.cc +++ fsck.cc @@ -0,0 +1,387 @@ +// copyright (C) 2005 derek scherger +// all rights reserved. +// licensed to the public under the terms of the GNU GPL (>= 2) +// see the file COPYING for details + +#include +#include + +#include "app_state.hh" +#include "fsck.hh" +#include "revision.hh" +#include "ui.hh" +#include "vocab.hh" + +struct checked_file { + int db_gets; // number of db.get's for this file which each check the sha1 + int manifest_refs; // number of manifest references to this file + + checked_file(): + db_gets(0), manifest_refs(0) {} +}; + +struct checked_manifest { + int db_gets; // number of db.get's for this manifest which each check the sha1 + int revision_refs; // number of revision references to this manifest + int missing_files; // number of missing files referenced by this manifest + + checked_manifest(): + db_gets(0), revision_refs(0), missing_files(0) {} +}; + +// revision refs should match ancestry parent refs +// number of parents should match ancestry child refs + +struct checked_revision { + int db_gets; // number of db.get's for this revision which each check the sha1 + int revision_refs; // number of references to this revision from other revisions + int ancestry_parent_refs; // number of references to this revision by ancestry parent + int ancestry_child_refs; // number of references to this revision by ancestry child + int missing_manifests; // number of manifests missing + int missing_revisions; // number of revisions missing + int incomplete_manifests; // number of manifests missing files referenced by this revision + + std::set parents; + + checked_revision(): + db_gets(0), + revision_refs(0), ancestry_parent_refs(0), ancestry_child_refs(0), + missing_manifests(0), missing_revisions(0), incomplete_manifests(0) {} +}; + +static void +check_files(app_state & app, std::map & checked_files) +{ + std::set files; + + app.db.get_file_ids(files); + L(F("checking %d files\n") % files.size()); + + ticker ticks("files", "f", files.size()/70+1); + + for (std::set::const_iterator i = files.begin(); + i != files.end(); ++i) + { + L(F("checking file %s\n") % *i); + file_data data; + app.db.get_file_version(*i, data); + checked_files[*i].db_gets++; + ++ticks; + } + + I(checked_files.size() == files.size()); +} + +static void +check_manifests(app_state & app, + std::map & checked_manifests, + std::map & checked_files) +{ + std::set manifests; + + app.db.get_manifest_ids(manifests); + L(F("checking %d manifests\n") % manifests.size()); + + ticker ticks("manifests", "m", manifests.size()/70+1); + + for (std::set::const_iterator i = manifests.begin(); + i != manifests.end(); ++i) + { + L(F("checking manifest %s\n") % *i); + manifest_data data; + app.db.get_manifest_version(*i, data); + checked_manifests[*i].db_gets++; + + manifest_map man; + read_manifest_map(data, man); + + for (manifest_map::const_iterator entry = man.begin(); entry != man.end(); + ++entry) + { + checked_files[manifest_entry_id(entry)].manifest_refs++; + + if (checked_files[manifest_entry_id(entry)].db_gets == 0) + checked_manifests[*i].missing_files++; + } + + ++ticks; + } + + I(checked_manifests.size() == manifests.size()); +} + +static void +check_revisions(app_state & app, + std::map & checked_revisions, + std::map & checked_manifests) +{ + std::set revisions; + + app.db.get_revision_ids(revisions); + L(F("checking %d revisions\n") % revisions.size()); + + ticker ticks("revisions", "r", revisions.size()/70+1); + + for (std::set::const_iterator i = revisions.begin(); + i != revisions.end(); ++i) + { + L(F("checking revision %s\n") % *i); + revision_data data; + app.db.get_revision(*i, data); + checked_revisions[*i].db_gets++; + + revision_set rev; + read_revision_set(data, rev); + + checked_manifests[rev.new_manifest].revision_refs++; + + if (checked_manifests[rev.new_manifest].db_gets == 0) + checked_revisions[*i].missing_manifests++; + + if (checked_manifests[rev.new_manifest].missing_files > 0) + checked_revisions[*i].incomplete_manifests++; + + for (edge_map::const_iterator edge = rev.edges.begin(); + edge != rev.edges.end(); ++edge) + { + // ignore [] -> [...] manifests + + if (!null_id(edge_old_manifest(edge))) + { + checked_manifests[edge_old_manifest(edge)].revision_refs++; + + if (checked_manifests[edge_old_manifest(edge)].db_gets == 0) + checked_revisions[*i].missing_manifests++; + + if (checked_manifests[edge_old_manifest(edge)].missing_files > 0) + checked_revisions[*i].incomplete_manifests++; + } + + // ignore [] -> [...] revisions + + // delay checking parents until we've processed all revisions + if (!null_id(edge_old_revision(edge))) + { + checked_revisions[edge_old_revision(edge)].revision_refs++; + checked_revisions[*i].parents.insert(edge_old_revision(edge)); + } + + // also check that change_sets applied to old manifests == new + // manifests (which might be a merge) + } + + ++ticks; + } + + // now check for parent revision existence and problems + + for (std::map::iterator + revision = checked_revisions.begin(); + revision != checked_revisions.end(); ++revision) + { + for (std::set::const_iterator p = revision->second.parents.begin(); + p != revision->second.parents.end(); ++p) + { + if (checked_revisions[*p].db_gets == 0) + revision->second.missing_revisions++; + } + } + + L(F("checked %d revisions after starting with %d\n") + % checked_revisions.size() + % revisions.size()); + + // I(checked_revisions.size() == revisions.size()); +} + +static void +check_ancestry(app_state & app, + std::map & checked_revisions) +{ + std::multimap graph; + + app.db.get_revision_ancestry(graph); + L(F("checking %d ancestry edges\n") % graph.size()); + + ticker ticks("ancestry", "a", graph.size()/70+1); + + // checked revision has set of parents + // graph has revision and associated parents + // these two representations of the graph should agree! + + std::set seen; + for (std::multimap::const_iterator i = graph.begin(); + i != graph.end(); ++i) + { + // ignore the [] -> [...] edges here too + if (!null_id(i->first)) + { + checked_revisions[i->first].ancestry_parent_refs++; + + if (!null_id(i->second)) + checked_revisions[i->second].ancestry_child_refs++; + } + + ++ticks; + } +} + +void +check_db(app_state & app) +{ + std::map checked_files; + std::map checked_manifests; + std::map checked_revisions; + + check_files(app, checked_files); + check_manifests(app, checked_manifests, checked_files); + check_revisions(app, checked_revisions, checked_manifests); + check_ancestry(app, checked_revisions); + + // revision certs + // public keys + + // report findings + + int missing_files = 0; + int unreferenced_files = 0; + + for (std::map::const_iterator + i = checked_files.begin(); i != checked_files.end(); ++i) + { + if (i->second.db_gets == 0) + { + missing_files++; + P(F("file %s missing (%d manifest references)\n") + % i->first % i->second.manifest_refs); + } + + if (i->second.manifest_refs == 0) + { + unreferenced_files++; + P(F("file %s unreferenced\n") % i->first); + } + + } + + int missing_manifests = 0; + int unreferenced_manifests = 0; + int incomplete_manifests = 0; + + for (std::map::const_iterator + i = checked_manifests.begin(); i != checked_manifests.end(); ++i) + { + if (i->second.db_gets == 0) + { + missing_manifests++; + P(F("manifest %s missing (%d revision references)\n") + % i->first % i->second.revision_refs); + } + + if (i->second.revision_refs == 0) + { + unreferenced_manifests++; + P(F("manifest %s unreferenced\n") % i->first); + } + + if (i->second.missing_files > 0) + { + incomplete_manifests++; + P(F("manifest %s incomplete (%d missing files)\n") + % i->first % i->second.missing_files); + } + } + + int missing_revisions = 0; + int incomplete_revisions = 0; + int mismatched_parents = 0; + int mismatched_children = 0; + + for (std::map::const_iterator + i = checked_revisions.begin(); i != checked_revisions.end(); ++i) + { + if (i->second.db_gets == 0) + { + missing_revisions++; + P(F("revision %s missing (%d revision references)\n") + % i->first % i->second.revision_refs); + } + + if (i->second.missing_manifests > 0) + { + incomplete_revisions++; + P(F("revision %s incomplete (%d missing manifests)\n") + % i->first % i->second.missing_manifests); + } + + if (i->second.missing_revisions > 0) + { + incomplete_revisions++; + P(F("revision %s incomplete (%d missing revisions)\n") + % i->first % i->second.missing_revisions); + } + + if (i->second.incomplete_manifests > 0) + { + incomplete_revisions++; + P(F("revision %s incomplete (%d incomplete manifests)\n") + % i->first % i->second.incomplete_manifests); + } + + if (i->second.ancestry_parent_refs != i->second.revision_refs) + { + mismatched_parents++; + P(F("revision %s mismatched parents (%d ancestry parents; %d revision refs)\n") + % i->first + % i->second.ancestry_parent_refs + % i->second.revision_refs ); + } + + if (i->second.ancestry_child_refs != i->second.parents.size()) + { + mismatched_children++; + P(F("revision %s mismatched children (%d ancestry children; %d parents)\n") + % i->first + % i->second.ancestry_child_refs + % i->second.parents.size() ); + } + } + + if (missing_files > 0) + W(F("%d missing files\n") % missing_files); + if (unreferenced_files > 0) + W(F("%d unreferenced files\n") % unreferenced_files); + + if (missing_manifests > 0) + W(F("%d missing manifests\n") % missing_manifests); + if (unreferenced_manifests > 0) + W(F("%d unreferenced manifests\n") % unreferenced_manifests); + if (incomplete_manifests > 0) + W(F("%d incomplete manifests\n") % incomplete_manifests); + + if (missing_revisions > 0) + W(F("%d missing revisions\n") % missing_revisions); + if (incomplete_revisions > 0) + W(F("%d incomplete revisions\n") % incomplete_revisions); + if (mismatched_parents > 0) + W(F("%d mismatched parents\n") % mismatched_parents); + if (mismatched_children > 0) + W(F("%d mismatched children\n") % mismatched_children); + + int total = missing_files + unreferenced_files + + missing_manifests + unreferenced_manifests + incomplete_manifests + + missing_revisions + incomplete_revisions + + mismatched_parents + mismatched_children; + + if (total > 0) + P(F("check complete: %d files; %d manifests; %d revisions; %d problems detected\n") + % checked_files.size() + % checked_manifests.size() + % checked_revisions.size() + % total); + else + P(F("check complete: %d files; %d manifests; %d revisions; database is good\n") + % checked_files.size() + % checked_manifests.size() + % checked_revisions.size()); +} --- fsck.hh +++ fsck.hh @@ -0,0 +1,14 @@ +#ifndef __FSCK_HH__ +#define __FSCK_HH__ + +// copyright (C) 2005 derek scherger +// all rights reserved. +// licensed to the public under the terms of the GNU GPL (>= 2) +// see the file COPYING for details + +#include "app_state.hh" + +void +check_db(app_state & app); + +#endif // header guard --- keys.cc +++ keys.cc @@ -7,13 +7,9 @@ #include -#include "cryptopp/arc4.h" -#include "cryptopp/base64.h" -#include "cryptopp/hex.h" -#include "cryptopp/cryptlib.h" -#include "cryptopp/osrng.h" -#include "cryptopp/sha.h" -#include "cryptopp/rsa.h" +#include "botan/botan.h" +#include "botan/rsa.h" +#include "botan/keypair.h" #include "constants.hh" #include "keys.hh" @@ -32,18 +28,20 @@ // there will probably forever be bugs in this file. it's very // hard to get right, portably and securely. sorry about that. -using namespace CryptoPP; +using namespace Botan; using namespace std; using boost::shared_ptr; +using boost::shared_dynamic_cast; static void -do_arc4(SecByteBlock & phrase, - SecByteBlock & payload) +do_arc4(SecureVector & phrase, + SecureVector & payload) { L(F("running arc4 process on %d bytes of data\n") % payload.size()); - ARC4 a4(phrase.data(), phrase.size()); - a4.ProcessString(payload.data(), payload.size()); + Pipe enc(get_cipher("ARC4", phrase, ENCRYPTION)); + enc.process_msg(payload); + payload = enc.read_all(); } // 'force_from_user' means that we don't use the passphrase cache, and we @@ -51,7 +49,7 @@ static void get_passphrase(lua_hooks & lua, rsa_keypair_id const & keyid, - SecByteBlock & phrase, + SecureVector & phrase, bool confirm_phrase = false, bool force_from_user = false, string prompt_beginning = "enter passphrase") @@ -68,14 +66,14 @@ if (!force_from_user && phrases.find(keyid) != phrases.end()) { string phr = phrases[keyid]; - phrase.Assign(reinterpret_cast(phr.data()), phr.size()); + phrase.set(reinterpret_cast(phr.data()), phr.size()); return; } if (!force_from_user && lua.hook_get_passphrase(keyid, lua_phrase)) { // user is being a slob and hooking lua to return his passphrase - phrase.Assign(reinterpret_cast(lua_phrase.data()), + phrase.set(reinterpret_cast(lua_phrase.data()), lua_phrase.size()); N(lua_phrase != "", F("got empty passphrase from get_passphrase() hook")); @@ -119,7 +117,7 @@ try { - phrase.Assign(reinterpret_cast(pass1), strlen(pass1)); + phrase.set(reinterpret_cast(pass1), strlen(pass1)); // permit security relaxation. maybe. if (persist_phrase) @@ -138,35 +136,7 @@ } } -template -static void -write_der(T & val, SecByteBlock & sec) -{ - // FIXME: this helper is *wrong*. I don't see how to DER-encode into a - // SecByteBlock, so we may well wind up leaving raw key bytes in malloc - // regions if we're not lucky. but we want to. maybe muck with - // AllocatorWithCleanup? who knows.. please fix! - string der_encoded; - try - { - StringSink der_sink(der_encoded); - val.DEREncode(der_sink); - der_sink.MessageEnd(); - sec.Assign(reinterpret_cast(der_encoded.data()), - der_encoded.size()); - L(F("wrote %d bytes of DER-encoded data\n") % der_encoded.size()); - } - catch (...) - { - for (size_t i = 0; i < der_encoded.size(); ++i) - der_encoded[i] = '\0'; - throw; - } - for (size_t i = 0; i < der_encoded.size(); ++i) - der_encoded[i] = '\0'; -} - void generate_key_pair(lua_hooks & lua, // to hook for phrase rsa_keypair_id const & id, // to prompting user for phrase @@ -174,41 +144,33 @@ base64< arc4 > & priv_out, string const unit_test_passphrase) { - // we will panic here if the user doesn't like urandom and we can't give - // them a real entropy-driven random. - bool request_blocking_rng = false; - if (!lua.hook_non_blocking_rng_ok()) - { -#ifndef BLOCKING_RNG_AVAILABLE - throw oops("no blocking RNG available and non-blocking RNG rejected"); -#else - request_blocking_rng = true; -#endif - } - AutoSeededRandomPool rng(request_blocking_rng); - SecByteBlock phrase, pubkey, privkey; + SecureVector phrase, pubkey, privkey; rsa_pub_key raw_pub_key; arc4 raw_priv_key; // generate private key (and encrypt it) - RSAES_OAEP_SHA_Decryptor priv(rng, constants::keylen); - write_der(priv, privkey); + RSA_PrivateKey priv(constants::keylen); + Pipe p; + p.start_msg(); + PKCS8::encode(priv, p, RAW_BER); + privkey = p.read_all(); + if (unit_test_passphrase.empty()) get_passphrase(lua, id, phrase, true, true); else - phrase.Assign(reinterpret_cast(unit_test_passphrase.c_str()), + phrase.set(reinterpret_cast(unit_test_passphrase.c_str()), unit_test_passphrase.size()); do_arc4(phrase, privkey); - raw_priv_key = string(reinterpret_cast(privkey.data()), - privkey.size()); + raw_priv_key = string(reinterpret_cast(privkey.begin()), privkey.size()); // generate public key - RSAES_OAEP_SHA_Encryptor pub(priv); - write_der(pub, pubkey); - raw_pub_key = string(reinterpret_cast(pubkey.data()), - pubkey.size()); + Pipe p2; + p2.start_msg(); + X509::encode(priv, p2, RAW_BER); + pubkey = p2.read_all(); + raw_pub_key = string(reinterpret_cast(pubkey.begin()), pubkey.size()); // if all that worked, we can return our results to caller encode_base64(raw_priv_key, priv_out); @@ -222,23 +184,23 @@ rsa_keypair_id const & id, base64< arc4 > & encoded_key) { - SecByteBlock phrase; + SecureVector phrase; get_passphrase(lua, id, phrase, false, true, "enter old passphrase"); arc4 decoded_key; - SecByteBlock key_block; + SecureVector key_block; decode_base64(encoded_key, decoded_key); - key_block.Assign(reinterpret_cast(decoded_key().data()), + key_block.set(reinterpret_cast(decoded_key().data()), decoded_key().size()); do_arc4(phrase, key_block); try { L(F("building signer from %d-byte decrypted private key\n") % key_block.size()); - StringSource keysource(key_block.data(), key_block.size(), true); - shared_ptr signer; - signer = shared_ptr - (new RSASSA_PKCS1v15_SHA_Signer(keysource)); + Pipe p; + p.process_msg(key_block); + shared_ptr pkcs8_key = + shared_ptr(PKCS8::load_key(p)); } catch (...) { @@ -248,48 +210,36 @@ get_passphrase(lua, id, phrase, true, true, "enter new passphrase"); do_arc4(phrase, key_block); - decoded_key = string(reinterpret_cast(key_block.data()), + decoded_key = string(reinterpret_cast(key_block.begin()), key_block.size()); encode_base64(decoded_key, encoded_key); } void -make_signature(lua_hooks & lua, // to hook for phrase +make_signature(app_state & app, // to hook for phrase rsa_keypair_id const & id, // to prompting user for phrase base64< arc4 > const & priv, string const & tosign, base64 & signature) { arc4 decoded_key; - SecByteBlock decrypted_key; - SecByteBlock phrase; + SecureVector decrypted_key; + SecureVector phrase; + SecureVector sig; string sig_string; - // we will panic here if the user doesn't like urandom and we can't give - // them a real entropy-driven random. - bool request_blocking_rng = false; - if (!lua.hook_non_blocking_rng_ok()) - { -#ifndef BLOCKING_RNG_AVAILABLE - throw oops("no blocking RNG available and non-blocking RNG rejected"); -#else - request_blocking_rng = true; -#endif - } - AutoSeededRandomPool rng(request_blocking_rng); - // we permit the user to relax security here, by caching a decrypted key // (if they permit it) through the life of a program run. this helps when // you're making a half-dozen certs during a commit or merge or // something. - static std::map > signers; - bool persist_phrase = (!signers.empty()) || lua.hook_persist_phrase_ok(); + bool persist_phrase = (!app.signers.empty()) || app.lua.hook_persist_phrase_ok(); bool force = false; - shared_ptr signer; - if (persist_phrase && signers.find(id) != signers.end()) - signer = signers[id]; + shared_ptr signer; + shared_ptr priv_key; + if (persist_phrase && app.signers.find(id) != app.signers.end()) + signer = app.signers[id].first; else { @@ -297,17 +247,19 @@ { L(F("base64-decoding %d-byte private key\n") % priv().size()); decode_base64(priv, decoded_key); - decrypted_key.Assign(reinterpret_cast(decoded_key().data()), + decrypted_key.set(reinterpret_cast(decoded_key().data()), decoded_key().size()); - get_passphrase(lua, id, phrase, false, force); - + get_passphrase(app.lua, id, phrase, false, force); + do_arc4(phrase, decrypted_key); + + L(F("building signer from %d-byte decrypted private key\n") % decrypted_key.size()); + + shared_ptr pkcs8_key; try { - do_arc4(phrase, decrypted_key); - L(F("building signer from %d-byte decrypted private key\n") % decrypted_key.size()); - StringSource keysource(decrypted_key.data(), decrypted_key.size(), true); - signer = shared_ptr - (new RSASSA_PKCS1v15_SHA_Signer(keysource)); + Pipe p; + p.process_msg(decrypted_key); + pkcs8_key = shared_ptr(PKCS8::load_key(p)); } catch (...) { @@ -318,24 +270,31 @@ force = true; continue; } + + priv_key = shared_dynamic_cast(pkcs8_key); + if (!priv_key) + throw informative_failure("Failed to get RSA signing key"); + + signer = shared_ptr(get_pk_signer(*priv_key, "EMSA3(SHA-1)")); + /* XXX This is ugly. We need to keep the key around as long + * as the signer is around, but the shared_ptr for the key will go + * away after we leave this scope. Hence we store a pair of + * so they both exist. */ if (persist_phrase) - signers.insert(make_pair(id,signer)); - break; + app.signers.insert(make_pair(id,make_pair(signer,priv_key))); } } - StringSource tmp(tosign, true, - new SignerFilter - (rng, *signer, - new StringSink(sig_string))); + sig = signer->sign_message(reinterpret_cast(tosign.data()), tosign.size()); + sig_string = string(reinterpret_cast(sig.begin()), sig.size()); L(F("produced %d-byte signature\n") % sig_string.size()); encode_base64(rsa_sha1_signature(sig_string), signature); } bool -check_signature(lua_hooks & lua, +check_signature(app_state &app, rsa_keypair_id const & id, base64 const & pub_encoded, string const & alleged_text, @@ -343,57 +302,51 @@ { // examine pubkey - static std::map > verifiers; - bool persist_phrase = (!verifiers.empty()) || lua.hook_persist_phrase_ok(); + bool persist_phrase = (!app.verifiers.empty()) || app.lua.hook_persist_phrase_ok(); - shared_ptr verifier; + shared_ptr verifier; + shared_ptr pub_key; if (persist_phrase - && verifiers.find(id) != verifiers.end()) - verifier = verifiers[id]; + && app.verifiers.find(id) != app.verifiers.end()) + verifier = app.verifiers[id].first; else { rsa_pub_key pub; decode_base64(pub_encoded, pub); - SecByteBlock pub_block; - pub_block.Assign(reinterpret_cast(pub().data()), pub().size()); - StringSource keysource(pub_block.data(), pub_block.size(), true); + SecureVector pub_block; + pub_block.set(reinterpret_cast(pub().data()), pub().size()); + L(F("building verifier for %d-byte pub key\n") % pub_block.size()); - verifier = shared_ptr - (new RSASSA_PKCS1v15_SHA_Verifier(keysource)); - + shared_ptr x509_key = + shared_ptr(X509::load_key(pub_block)); + pub_key = shared_dynamic_cast(x509_key); + if (!pub_key) + throw informative_failure("Failed to get RSA verifying key"); + + verifier = shared_ptr(get_pk_verifier(*pub_key, "EMSA3(SHA-1)")); + + /* XXX This is ugly. We need to keep the key around + * as long as the verifier is around, but the shared_ptr will go + * away after we leave this scope. Hence we store a pair of + * so they both exist. */ if (persist_phrase) - verifiers.insert(make_pair(id, verifier)); + app.verifiers.insert(make_pair(id, make_pair(verifier, pub_key))); } // examine signature rsa_sha1_signature sig_decoded; decode_base64(signature, sig_decoded); - if (sig_decoded().size() != verifier->SignatureLength()) - return false; // check the text+sig against the key L(F("checking %d-byte (%d decoded) signature\n") % signature().size() % sig_decoded().size()); - VerifierFilter * vf = NULL; - // crypto++ likes to use pointers in ways which boost and std:: smart - // pointers aren't really good with, unfortunately. - try - { - vf = new VerifierFilter(*verifier); - vf->Put(reinterpret_cast(sig_decoded().data()), sig_decoded().size()); - } - catch (...) - { - if (vf) - delete vf; - throw; - } + bool valid_sig = verifier->verify_message( + reinterpret_cast(alleged_text.data()), alleged_text.size(), + reinterpret_cast(sig_decoded().data()), sig_decoded().size()); - I(vf); - StringSource tmp(alleged_text, true, vf); - return vf->GetLastResult(); + return valid_sig; } void @@ -455,8 +408,8 @@ { string plaintext("hi maude"); base64 sig; - make_signature(app.lua, key, priv, plaintext, sig); - N(check_signature(app.lua, key, pub, plaintext, sig), + make_signature(app, key, priv, plaintext, sig); + N(check_signature(app, key, pub, plaintext, sig), F("passphrase for '%s' is incorrect") % key); } } @@ -464,82 +417,64 @@ #ifdef BUILD_UNIT_TESTS #include "unit_tests.hh" +static void +arc4_test() +{ + + string pt("new fascist tidiness regime in place"); + string phr("still spring water"); + + SecureVector phrase(reinterpret_cast(phr.data()), + phr.size()); + + SecureVector orig(reinterpret_cast(pt.data()), + pt.size()); + + SecureVector data(orig); + + BOOST_CHECKPOINT("encrypting data"); + do_arc4(phrase, data); + + BOOST_CHECK(data != orig); + + BOOST_CHECKPOINT("decrypting data"); + do_arc4(phrase, data); + + BOOST_CHECK(data == orig); + +} + static void signature_round_trip_test() { - lua_hooks lua; - lua.add_std_hooks(); - lua.add_test_hooks(); - + app_state app; + app.lua.add_std_hooks(); + app.lua.add_test_hooks(); + BOOST_CHECKPOINT("generating key pairs"); rsa_keypair_id key("address@hidden"); base64 pubkey; base64< arc4 > privkey; - generate_key_pair(lua, key, pubkey, privkey, "address@hidden"); + generate_key_pair(app.lua, key, pubkey, privkey, "address@hidden"); BOOST_CHECKPOINT("signing plaintext"); string plaintext("test string to sign"); base64 sig; - make_signature(lua, key, privkey, plaintext, sig); + make_signature(app, key, privkey, plaintext, sig); BOOST_CHECKPOINT("checking signature"); - BOOST_CHECK(check_signature(lua, key, pubkey, plaintext, sig)); + BOOST_CHECK(check_signature(app, key, pubkey, plaintext, sig)); string broken_plaintext = plaintext + " ...with a lie"; BOOST_CHECKPOINT("checking non-signature"); - BOOST_CHECK(!check_signature(lua, key, pubkey, broken_plaintext, sig)); + BOOST_CHECK(!check_signature(app, key, pubkey, broken_plaintext, sig)); } -static void -osrng_test() -{ - AutoSeededRandomPool rng_random(true), rng_urandom(false); - - for (int round = 0; round < 20; ++round) - { - MaurerRandomnessTest t_blank, t_urandom, t_random; - int i = 0; - - while (t_blank.BytesNeeded() != 0) - { - t_blank.Put(static_cast(0)); - i++; - } - L(F("%d bytes blank input -> tests as %f randomness\n") - % i % t_blank.GetTestValue()); - - - i = 0; - while (t_urandom.BytesNeeded() != 0) - { - t_urandom.Put(rng_urandom.GenerateByte()); - i++; - } - L(F("%d bytes urandom-seeded input -> tests as %f randomness\n") - % i % t_urandom.GetTestValue()); - - - i = 0; - while (t_random.BytesNeeded() != 0) - { - t_random.Put(rng_random.GenerateByte()); - i++; - } - - L(F("%d bytes random-seeded input -> tests as %f randomness\n") - % i % t_random.GetTestValue()); - - BOOST_CHECK(t_blank.GetTestValue() == 0.0); - BOOST_CHECK(t_urandom.GetTestValue() > 0.95); - BOOST_CHECK(t_random.GetTestValue() > 0.95); - } -} - void add_key_tests(test_suite * suite) { I(suite); - suite->add(BOOST_TEST_CASE(&osrng_test)); + suite->add(BOOST_TEST_CASE(&arc4_test)); suite->add(BOOST_TEST_CASE(&signature_round_trip_test)); } --- keys.hh +++ keys.hh @@ -27,13 +27,13 @@ rsa_keypair_id const & id, // to prompting user for phrase base64< arc4 > & encoded_key); -void make_signature(lua_hooks & lua, // to hook for phrase +void make_signature(app_state & app, // to hook for phrase rsa_keypair_id const & id, // to prompting user for phrase base64< arc4 > const & priv, std::string const & tosign, base64 & signature); -bool check_signature(lua_hooks & lua, +bool check_signature(app_state & app, rsa_keypair_id const & id, base64 const & pub, std::string const & alleged_text, --- main.cc +++ main.cc @@ -261,6 +261,7 @@ struct sigaction old_SIGSEGV_action; struct sigaction old_SIGBUS_action; struct sigaction old_SIGABRT_action; + struct sigaction old_SIGPIPE_action; all_signals_action.sa_flags = 0; all_signals_action.sa_handler = &unix_style_signal_handler; @@ -272,6 +273,13 @@ sigaction(SIGBUS , &all_signals_action, &old_SIGBUS_action); sigaction(SIGABRT, &all_signals_action, &old_SIGABRT_action); + // We want to ignore SIGPIPE for netxx + struct sigaction ignore_signals_action; + ignore_signals_action.sa_flags = 0; + ignore_signals_action.sa_handler = SIG_IGN; + sigemptyset(&ignore_signals_action.sa_mask); + sigaction(SIGPIPE, &ignore_signals_action, &old_SIGPIPE_action); + int result = 0; bool trapped_signal = false; char const *em = NULL; @@ -311,6 +319,7 @@ sigaction(SIGSEGV, &old_SIGSEGV_action, sigaction_ptr()); sigaction(SIGBUS , &old_SIGBUS_action , sigaction_ptr()); sigaction(SIGABRT, &old_SIGABRT_action, sigaction_ptr()); + sigaction(SIGPIPE, &old_SIGPIPE_action, NULL); if(trapped_signal) throw unix_signal_exception(em); --- merkle_tree.cc +++ merkle_tree.cc @@ -10,7 +10,8 @@ #include -#include "cryptopp/sha.h" +#include "botan/botan.h" +#include "botan/sha160.h" #include "constants.hh" #include "merkle_tree.hh" @@ -21,7 +22,6 @@ using namespace boost; using namespace std; -using namespace CryptoPP; void netcmd_item_type_to_string(netcmd_item_type t, string & typestr) @@ -59,12 +59,12 @@ string raw_sha1(string const & in) { - SHA hash; - hash.Update(reinterpret_cast(in.data()), - static_cast(in.size())); - char digest[SHA::DIGESTSIZE]; - hash.Final(reinterpret_cast(digest)); - string out(digest, SHA::DIGESTSIZE); + Botan::SHA_160 hash; + hash.update(reinterpret_cast(in.data()), + static_cast(in.size())); + char digest[hash.OUTPUT_LENGTH]; + hash.final(reinterpret_cast(digest)); + string out(digest, hash.OUTPUT_LENGTH); return out; } @@ -315,7 +315,7 @@ out.check_invariants(); if (hash != checkhash) throw bad_decode(F("mismatched node hash value %s, expected %s") - % xform(checkhash) % xform(hash)); + % xform(checkhash) % xform(hash)); } --- mkstemp.cc +++ mkstemp.cc @@ -15,8 +15,8 @@ #include #include -#include "cryptopp/osrng.h" #include "file_io.hh" +#include "botan/botan.h" #ifndef O_BINARY #define O_BINARY 0 @@ -34,7 +34,6 @@ static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static const int NLETTERS = sizeof (letters) - 1; - static CryptoPP::AutoSeededRandomPool mkstemp_urandom; len = tmpl.length(); if (len < 6 || tmpl.rfind("XXXXXX") != len-6) @@ -45,7 +44,7 @@ tmp = tmpl.substr(0, len-6); for (i = 0; i < 6; ++i) - tmp.append(1, letters[mkstemp_urandom.GenerateByte() % NLETTERS]); + tmp.append(1, letters[Botan::Global_RNG::random(Botan::Nonce) % NLETTERS]); fd = open(tmp.c_str(), O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); if (fd >= 0) { --- monotone.cc +++ monotone.cc @@ -18,6 +18,8 @@ #include #endif +#include "botan/botan.h" + #include "app_state.hh" #include "commands.hh" #include "sanity.hh" @@ -107,6 +109,8 @@ { if (!clean_shutdown) global_sanity.dump_buffer(); + + Botan::Init::deinitialize(); } @@ -226,6 +230,9 @@ L(F("set locale: LC_CTYPE=%s, LC_MESSAGES=%s\n") % (setlocale(LC_CTYPE, NULL) == NULL ? "n/a" : setlocale(LC_CTYPE, NULL)) % (setlocale(LC_MESSAGES, NULL) == NULL ? "n/a" : setlocale(LC_CTYPE, NULL))); + + // Set up secure memory allocation etc + Botan::Init::initialize(); // decode all argv values into a UTF-8 array --- netcmd.cc +++ netcmd.cc @@ -7,7 +7,8 @@ #include #include -#include "cryptopp/gzip.h" +#include "botan/botan.h" +#include "botan/gzip.h" #include "adler32.hh" #include "constants.hh" @@ -396,7 +397,7 @@ u8 compressed_p = extract_datum_lsb(in, pos, "data netcmd, compression flag"); extract_variable_length_string(in, dat, pos, "data netcmd, data payload"); if (compressed_p == 1) - dat = xform(dat); + dat = xform(dat); assert_end_of_buffer(in, pos, "data netcmd payload"); } @@ -412,7 +413,7 @@ if (dat.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip) { string tmp; - tmp = xform(dat); + tmp = xform(dat); out += static_cast(1); // compressed flag insert_variable_length_string(tmp, out); } @@ -441,7 +442,7 @@ string tmp; extract_variable_length_string(in, tmp, pos, "delta netcmd, delta payload"); if (compressed_p == 1) - tmp = xform(tmp); + tmp = xform(tmp); del = delta(tmp); assert_end_of_buffer(in, pos, "delta netcmd payload"); } @@ -462,7 +463,7 @@ if (tmp.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip) { out += static_cast(1); // compressed flag - tmp = xform(tmp); + tmp = xform(tmp); } else { --- netsync.cc +++ netsync.cc @@ -30,7 +30,7 @@ #include "epoch.hh" #include "platform.hh" -#include "cryptopp/osrng.h" +#include "botan/botan.h" #include "netxx/address.h" #include "netxx/peer.h" @@ -246,7 +246,6 @@ id saved_nonce; bool received_goodbye; bool sent_goodbye; - boost::scoped_ptr prng; packet_db_valve dbw; @@ -449,19 +448,6 @@ this->collection = idx(collections, 0); } - // we will panic here if the user doesn't like urandom and we can't give - // them a real entropy-driven random. - bool request_blocking_rng = false; - if (!app.lua.hook_non_blocking_rng_ok()) - { -#ifndef BLOCKING_RNG_AVAILABLE - throw oops("no blocking RNG available and non-blocking RNG rejected"); -#else - request_blocking_rng = true; -#endif - } - prng.reset(new CryptoPP::AutoSeededRandomPool(request_blocking_rng)); - done_refinements.insert(make_pair(cert_item, done_marker())); done_refinements.insert(make_pair(key_item, done_marker())); done_refinements.insert(make_pair(epoch_item, done_marker())); @@ -485,7 +471,8 @@ { I(this->saved_nonce().size() == 0); char buf[constants::merkle_hash_length_in_bytes]; - prng->GenerateBlock(reinterpret_cast(buf), constants::merkle_hash_length_in_bytes); + Botan::Global_RNG::randomize(reinterpret_cast(buf), + constants::merkle_hash_length_in_bytes); this->saved_nonce = string(buf, buf + constants::merkle_hash_length_in_bytes); I(this->saved_nonce().size() == constants::merkle_hash_length_in_bytes); return this->saved_nonce; @@ -1491,7 +1478,7 @@ rsa_sha1_signature sig_raw; base64< arc4 > our_priv; load_priv_key(app, app.signing_key, our_priv); - make_signature(app.lua, app.signing_key, our_priv, nonce(), sig); + make_signature(app, app.signing_key, our_priv, nonce(), sig); decode_base64(sig, sig_raw); // make a new nonce of our own and send off the 'auth' @@ -1571,7 +1558,7 @@ rsa_sha1_signature sig_raw; base64< arc4 > our_priv; load_priv_key(app, app.signing_key, our_priv); - make_signature(app.lua, app.signing_key, our_priv, nonce2(), sig); + make_signature(app, app.signing_key, our_priv, nonce2(), sig); decode_base64(sig, sig_raw); queue_confirm_cmd(sig_raw()); this->collection = collection; @@ -1684,7 +1671,7 @@ // check the signature base64 sig; encode_base64(rsa_sha1_signature(signature), sig); - if (check_signature(app.lua, their_id, their_key, nonce1(), sig)) + if (check_signature(app, their_id, their_key, nonce1(), sig)) { // get our private key and sign back L(F("client signature OK, accepting authentication\n")); @@ -1692,7 +1679,7 @@ rsa_sha1_signature sig_raw; base64< arc4 > our_priv; load_priv_key(app, app.signing_key, our_priv); - make_signature(app.lua, app.signing_key, our_priv, nonce2(), sig); + make_signature(app, app.signing_key, our_priv, nonce2(), sig); decode_base64(sig, sig_raw); queue_confirm_cmd(sig_raw()); this->collection = collection; @@ -1744,7 +1731,7 @@ app.db.get_pubkey(their_key_hash, their_id, their_key); base64 sig; encode_base64(rsa_sha1_signature(signature), sig); - if (check_signature(app.lua, their_id, their_key, this->saved_nonce(), sig)) + if (check_signature(app, their_id, their_key, this->saved_nonce(), sig)) { L(F("server signature OK, accepting authentication\n")); this->authenticated = true; --- revision.cc +++ revision.cc @@ -19,7 +19,7 @@ #include #include -#include "cryptopp/osrng.h" +#include "botan/botan.h" #include "basic_io.hh" #include "change_set.hh" @@ -1142,12 +1142,11 @@ { // regenerate epochs on all branches to random states - CryptoPP::AutoSeededRandomPool prng; for (std::set::const_iterator i = branches.begin(); i != branches.end(); ++i) { char buf[constants::epochlen_bytes]; - prng.GenerateBlock(reinterpret_cast(buf), constants::epochlen_bytes); + Botan::Global_RNG::randomize(reinterpret_cast(buf), constants::epochlen_bytes); hexenc hexdata; encode_hexenc(data(std::string(buf, buf + constants::epochlen_bytes)), hexdata); epoch_data new_epoch(hexdata); --- schema_migration.cc +++ schema_migration.cc @@ -15,9 +15,7 @@ #include #include "schema_migration.hh" -#include "cryptopp/filters.h" -#include "cryptopp/sha.h" -#include "cryptopp/hex.h" +#include "botan/botan.h" // this file knows how to migrate schema databases. the general strategy is // to hash each schema we ever use, and make a list of the SQL commands @@ -73,14 +71,10 @@ calculate_id(string const & in, string & ident) { - CryptoPP::SHA hash; - unsigned int const sz = 2 * CryptoPP::SHA::DIGESTSIZE; - char buffer[sz]; - CryptoPP::StringSource - s(in, true, new CryptoPP::HashFilter - (hash, new CryptoPP::HexEncoder - (new CryptoPP::ArraySink(reinterpret_cast(buffer), sz)))); - ident = lowercase(string(buffer, sz)); + Botan::Pipe p(new Botan::Hash_Filter("SHA-1"), new Botan::Hex_Encoder()); + p.process_msg(in); + + ident = lowercase(p.read_all_as_string()); } --- tests/t_database_check.at +++ tests/t_database_check.at @@ -30,11 +30,11 @@ # 80536d31e18d514e52983a5dbac8e19d66b564dd NEWS AT_DATA(manifestX, [@<:@mdata 1845ba581ec220b33fd14c7ca389576c5b97e959@:>@ -H4sICDSlGkIAA2FzZGYAFY/LTkMxDAX39yvyBSjxI7aXFUJQqbSIFiGWTuIUxOv/d4T90ZyZ -1gSoC4ZNmXkMp1LcFQuWXkm52OiZCqa0e7k8nJ7P25oOUGrYSd3QQoGyDO44vXaL3CbH7C2l -29PT2/54vwmJgJNZqwLB3JtilZis2UlJshU1/v+4ffefaxx+r5ubWkEGEppSpeuAiLbEyAuU -oDoFFghS2h/Pl93hsFXLBpWHYsvgSy97G6qryqt3q6MRIODyevTPmB9fcePfm2bGOrBE0cGF -gsEUnUfzrrHia21caYyUjnev5+0P6L2WtS8BAAA= +H4sIAAAAAAAAAxWPy05DMQwF9/cr8gUo8SO2lxVCUKm0iBYhlk7iFMTr/3eE/dGcmdYEqAuG +TZl5DKdS3BULll5JudjomQqmtHu5PJyez9uaDlBq2End0EKBsgzuOL12i9wmx+wtpdvT09v+ +eL8JiYCTWasCwdybYpWYrNlJSbIVNf7/uH33n2scfq+bm1pBBhKaUqXrgIi2xMgLlKA6BRYI +Utofz5fd4bBVywaVh2LL4Esvexuqq8qrd6ujESDg8nr0z5gfX3Hj35tmxjqwRNHBhYLBFJ1H +866x4mttXGmMlI53r+ftD+i9lrUvAQAA @<:@end@:>@ ]) --- tests/t_fsck.at +++ tests/t_fsck.at @@ -0,0 +1,100 @@ +# -*- Autoconf -*- + +AT_SETUP([database fsck]) + +MONOTONE_SETUP + +AT_DATA(file1, [file 1 +]) +AT_DATA(file2, [file 2 +]) +AT_DATA(file3, [file 3 +]) + +# fileX is not referenced by any manifest we have + +AT_DATA(fileX, [@<:@fdata ff43181b2988e27db1d63605bb3e39d4f06148cb@:>@ +H4sIAAAAAAAAAFNQUEjLzElVUEpJTcpMzNMvKs1JLVbiSq1ITS4tAQqXFJWmKnEBADUsgmsm +AAAA +@<:@end@:>@ +]) + +# manifestX below contains the following 6 files, none of which are +# present in the database +# +# bb724c73e9f7f0dda411aa83131c648519dc0413 AUTHORS +# 3e9d284b3c48a939e82407d5c3fa6c9e0bf5efcb COPYING +# 74772a499b672e55cb8367ef580a484709189513 ChangeLog +# a9891352474f767c8d2eeba834a121e46f725cb2 INSTALL +# 6909265d83b02ab3c0abd887f0a6ac96db42323b Makefile.am +# 80536d31e18d514e52983a5dbac8e19d66b564dd NEWS + +AT_DATA(manifestX, [@<:@mdata 1845ba581ec220b33fd14c7ca389576c5b97e959@:>@ +H4sICDSlGkIAA2FzZGYAFY/LTkMxDAX39yvyBSjxI7aXFUJQqbSIFiGWTuIUxOv/d4T90ZyZ +1gSoC4ZNmXkMp1LcFQuWXkm52OiZCqa0e7k8nJ7P25oOUGrYSd3QQoGyDO44vXaL3CbH7C2l +29PT2/54vwmJgJNZqwLB3JtilZis2UlJshU1/v+4ffefaxx+r5ubWkEGEppSpeuAiLbEyAuU +oDoFFghS2h/Pl93hsFXLBpWHYsvgSy97G6qryqt3q6MRIODyevTPmB9fcePfm2bGOrBE0cGF +gsEUnUfzrrHia21caYyUjnev5+0P6L2WtS8BAAA= +@<:@end@:>@ +]) + +AT_CHECK(MONOTONE add file1, [], [ignore], [ignore]) +AT_CHECK(MONOTONE commit --branch=test --message='add file1', [], [ignore], [ignore]) +REV1=`BASE_REVISION` +MAN1=`monotone --norc cat manifest | monotone --norc identify` + +AT_CHECK(MONOTONE add file2, [], [ignore], [ignore]) +AT_CHECK(MONOTONE commit --branch=test --message='add file2', [], [ignore], [ignore]) +FILE2=`SHA1(file2)` + +AT_CHECK(MONOTONE add file3, [], [ignore], [ignore]) +AT_CHECK(MONOTONE commit --branch=test --message='add file3', [], [ignore], [ignore]) + +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep 'database is good' stderr, [], [ignore], [ignore]) + +# remove file2 from the database invalidating manifest2 and manifest3 +# both of which include this file + +AT_CHECK(MONOTONE db execute "delete from files where id='$FILE2'", [], [ignore], [ignore]) + +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep 'database is good' stderr, [1], [ignore], [ignore]) +AT_CHECK(grep 'problems detected' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep 'missing file' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep 'incomplete manifest' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep 'incomplete revision' stderr, [0], [ignore], [ignore]) + +# add an unreferenced file, and an unreferenced manifest that +# references several files, none of which exist in the db + +AT_CHECK(MONOTONE read < fileX, [], [ignore], [ignore]) +AT_CHECK(MONOTONE read < manifestX, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep 'unreferenced file' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep 'unreferenced manifest' stderr, [0], [ignore], [ignore]) + +AT_CHECK(MONOTONE db execute "delete from revision_ancestry", [], [ignore], [ignore]) +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep 'mismatched parent' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep 'mismatched child' stderr, [0], [ignore], [ignore]) + +XDELTA_CC="877cfe29db0f60dec63439857fe78673b9d55346" +XDELTA_HH="68d15dc01398c7bb375b1a90fbb420bebef1bac7" + +AT_CHECK(MONOTONE db execute "insert into revision_ancestry values('$XDELTA_CC', '$XDELTA_HH')", [], [ignore], [ignore]) +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep 'mismatched parent' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep 'mismatched child' stderr, [0], [ignore], [ignore]) +AT_CHECK(grep '2 missing revision' stderr, [0], [ignore], [ignore]) + +AT_CHECK(MONOTONE db execute "delete from manifest_deltas where id='$MAN1'", [], [ignore], [ignore]) +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep 'missing manifest' stderr, [0], [ignore], [ignore]) + +AT_CHECK(MONOTONE db execute "delete from revisions where id='$REV1'", [], [ignore], [ignore]) +AT_CHECK(MONOTONE db fsck, [], [ignore], [stderr]) +AT_CHECK(grep '3 missing revision' stderr, [0], [ignore], [ignore]) + +AT_CLEANUP --- tests/t_netsync_unrelated.at +++ tests/t_netsync_unrelated.at @@ -16,6 +16,12 @@ # mentioned there; doing sideways deltas between heads, all sorts of # possibilities for maybe-efficient algorithms. +# For analysis and discussion of solutions, see: +# http://lists.gnu.org/archive/html/monotone-devel/2004-11/msg00043.html +# There are other strategies that might be good besides the one +# mentioned there; doing sideways deltas between heads, all sorts of +# possibilities for maybe-efficient algorithms. + # This test is a bug report. AT_XFAIL_IF(true) --- transforms.cc +++ transforms.cc @@ -14,12 +14,9 @@ #include #include -#include "cryptopp/filters.h" -#include "cryptopp/files.h" -#include "cryptopp/sha.h" -#include "cryptopp/hex.h" -#include "cryptopp/base64.h" -#include "cryptopp/gzip.h" +#include "botan/botan.h" +#include "botan/gzip.h" +#include "botan/sha160.h" #include "idna/idna.h" #include "idna/stringprep.h" @@ -65,20 +62,19 @@ template string xform(string const & in) { string out; - out.reserve(in.size() * 2); - CryptoPP::StringSource - str(in, true, - new XFM(new CryptoPP::StringSink(out))); + Botan::Pipe pipe(new XFM()); + pipe.process_msg(in); + out = pipe.read_all_as_string(); return out; } // specialize it -template string xform(string const &); -template string xform(string const &); -template string xform(string const &); -template string xform(string const &); -template string xform(string const &); -template string xform(string const &); +template string xform(string const &); +template string xform(string const &); +template string xform(string const &); +template string xform(string const &); +template string xform(string const &); +template string xform(string const &); // for use in hexenc encoding @@ -192,14 +188,10 @@ calculate_ident(data const & dat, hexenc & ident) { - CryptoPP::SHA hash; - hash.Update(reinterpret_cast(dat().c_str()), - static_cast(dat().size())); - char digest[CryptoPP::SHA::DIGESTSIZE]; - hash.Final(reinterpret_cast(digest)); - string out(digest, CryptoPP::SHA::DIGESTSIZE); - id ident_decoded(out); - encode_hexenc(ident_decoded, ident); + Botan::Pipe p(new Botan::Hash_Filter("SHA-1")); + p.process_msg(dat()); + + encode_hexenc(id(p.read_all_as_string()), ident); } void @@ -226,7 +218,6 @@ calculate_ident(manifest_map const & m, manifest_id & ident) { - CryptoPP::SHA hash; size_t sz = 0; static size_t bufsz = 0; static char *buf = NULL; @@ -260,16 +251,12 @@ *c++ = '\n'; } - hash.Update(reinterpret_cast(buf), - static_cast(sz)); + Botan::Pipe p(new Botan::Hash_Filter("SHA-1")); + p.process_msg(reinterpret_cast(buf), sz); - char digest[CryptoPP::SHA::DIGESTSIZE]; - hash.Final(reinterpret_cast(digest)); - string out(digest, CryptoPP::SHA::DIGESTSIZE); - id ident_decoded(out); - hexenc raw_ident; - encode_hexenc(ident_decoded, raw_ident); - ident = manifest_id(raw_ident); + hexenc tmp; + encode_hexenc(id(p.read_all_as_string()), tmp); + ident = manifest_id(tmp); } void @@ -326,13 +313,11 @@ else { // no conversions necessary, use streaming form - CryptoPP::SHA hash; - unsigned int const sz = 2 * CryptoPP::SHA::DIGESTSIZE; - char buffer[sz]; - CryptoPP::FileSource f(file().c_str(), true, new CryptoPP::HashFilter - (hash, new CryptoPP::HexEncoder - (new CryptoPP::ArraySink(reinterpret_cast(buffer), sz)))); - ident = lowercase(string(buffer, sz)); + Botan::Pipe p(new Botan::Hash_Filter("SHA-1"), new Botan::Hex_Encoder()); + Botan::DataSource_Stream infile(file()); + p.process_msg(infile); + + ident = lowercase(p.read_all_as_string()); } } @@ -473,8 +458,8 @@ string canonical_base64(string const & s) { - return xform - (xform(s)); + return xform + (xform(s)); } --- transforms.hh +++ transforms.hh @@ -18,32 +18,32 @@ // transforms.cc for the implementations (most of which are delegations to // crypto++ and librsync) -namespace CryptoPP { - class Base64Encoder; - class Base64Decoder; - class HexEncoder; - class HexDecoder; - class Gzip; - class Gunzip; +namespace Botan { + class Base64_Encoder; + class Base64_Decoder; + class Hex_Encoder; + class Hex_Decoder; + class Gzip_Compression; + class Gzip_Decompression; } template std::string xform(std::string const &); -extern template std::string xform(std::string const &); -extern template std::string xform(std::string const &); -extern template std::string xform(std::string const &); -extern template std::string xform(std::string const &); -extern template std::string xform(std::string const &); -extern template std::string xform(std::string const &); +extern template std::string xform(std::string const &); +extern template std::string xform(std::string const &); +extern template std::string xform(std::string const &); +extern template std::string xform(std::string const &); +extern template std::string xform(std::string const &); +extern template std::string xform(std::string const &); // base64 encoding template void encode_base64(T const & in, base64 & out) -{ out = xform(in()); } +{ out = xform(in()); } template void decode_base64(base64 const & in, T & out) -{ out = xform(in()); } +{ out = xform(in()); } // hex encoding @@ -53,22 +53,22 @@ template void decode_hexenc(hexenc const & in, T & out) -{ out = xform(uppercase(in())); } +{ out = xform(uppercase(in())); } template void encode_hexenc(T const & in, hexenc & out) -{ out = lowercase(xform(in())); } +{ out = lowercase(xform(in())); } // gzip template void encode_gzip(T const & in, gzip & out) -{ out = xform(in()); } +{ out = xform(in()); } template void decode_gzip(gzip const & in, T & out) -{ out = xform(in()); } +{ out = xform(in()); } // both at once (this is relatively common) --- unit_tests.cc +++ unit_tests.cc @@ -6,6 +6,8 @@ #include +#include "botan/botan.h" + #include "unit_tests.hh" #include "sanity.hh" @@ -17,6 +19,7 @@ { if (!clean_shutdown) global_sanity.dump_buffer(); + Botan::Init::deinitialize(); } void clean_shutdown_dummy_test() @@ -26,6 +29,8 @@ test_suite * init_unit_test_suite(int argc, char * argv[]) { + Botan::Init::initialize(); + clean_shutdown = false; atexit(&dumper); global_sanity.set_debug(); --- unix/inodeprint.cc +++ unix/inodeprint.cc @@ -5,7 +5,8 @@ #include -#include "cryptopp/sha.h" +#include "botan/botan.h" +#include "botan/sha160.h" #include "platform.hh" #include "transforms.hh" @@ -13,15 +14,15 @@ namespace { template void - add_hash(CryptoPP::SHA & hash, T obj) + add_hash(Botan::SHA_160 & hash, T obj) { // FIXME: this is not endian safe, which will cause problems // if the inodeprint listing is shared between machines of // different types (over NFS etc). size_t size = sizeof(obj); - hash.Update(reinterpret_cast(&size), + hash.update(reinterpret_cast(&size), sizeof(size)); - hash.Update(reinterpret_cast(&obj), + hash.update(reinterpret_cast(&obj), sizeof(obj)); } }; @@ -32,7 +33,7 @@ if (stat(file().c_str(), &st) < 0) return false; - CryptoPP::SHA hash; + Botan::SHA_160 hash; add_hash(hash, st.st_ctime); @@ -66,9 +67,9 @@ add_hash(hash, st.st_gid); add_hash(hash, st.st_size); - char digest[CryptoPP::SHA::DIGESTSIZE]; - hash.Final(reinterpret_cast(digest)); - std::string out(digest, CryptoPP::SHA::DIGESTSIZE); + char digest[hash.OUTPUT_LENGTH]; + hash.final(reinterpret_cast(digest)); + std::string out(digest, hash.OUTPUT_LENGTH); inodeprint ip_raw(out); encode_hexenc(ip_raw, ip); return true; --- work.hh +++ work.hh @@ -84,6 +84,8 @@ bool has_contents_user_log(); +bool has_contents_user_log(); + // the "options map" is another administrative file, stored in // MT/options. it keeps a list of name/value pairs which are considered // "persistent options", associated with a particular the working copy and