summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--crypto/Kconfig5
-rw-r--r--crypto/Makefile2
-rw-r--r--crypto/userspace/Makefile70
-rw-r--r--crypto/userspace/cryptodev_cipher.c381
-rw-r--r--crypto/userspace/cryptodev_int.h84
-rw-r--r--crypto/userspace/cryptodev_main.c229
-rw-r--r--crypto/userspace/libtomcrypt/hashes/crypt_hash_is_valid.c30
-rw-r--r--crypto/userspace/libtomcrypt/hashes/hash_get_oid.c78
-rw-r--r--crypto/userspace/libtomcrypt/hashes/hash_memory.c66
-rw-r--r--crypto/userspace/libtomcrypt/hashes/hash_memory_multi.c84
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt.h84
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_argchk.h36
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_cfg.h135
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_custom.h408
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_hash.h14
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_macros.h424
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_math.h13
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_misc.h23
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_pk.h359
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_pkcs.h67
-rw-r--r--crypto/userspace/libtomcrypt/headers/tomcrypt_prng.h80
-rw-r--r--crypto/userspace/libtomcrypt/math/rand_prime.c80
-rw-r--r--crypto/userspace/libtomcrypt/misc/crypt/crypt_argchk.c28
-rw-r--r--crypto/userspace/libtomcrypt/misc/pk_get_oid.c40
-rw-r--r--crypto/userspace/libtomcrypt/misc/zeromem.c34
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_decode_bit_string.c106
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_encode_bit_string.c92
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_length_bit_string.c54
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_decode_boolean.c47
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_encode_boolean.c51
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_length_boolean.c35
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/choice/der_decode_choice.c182
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_decode_ia5_string.c96
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_encode_ia5_string.c85
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_length_ia5_string.c194
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_decode_integer.c110
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_encode_integer.c130
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_length_integer.c82
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_decode_object_identifier.c99
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_encode_object_identifier.c111
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_length_object_identifier.c89
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_decode_octet_string.c91
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_encode_octet_string.c86
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_length_octet_string.c53
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_decode_printable_string.c96
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_encode_printable_string.c85
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_length_printable_string.c166
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_ex.c287
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_flexi.c394
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_multi.c140
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_ex.c335
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_multi.c139
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_length_sequence.c169
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_sequence_free.c66
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_set.c104
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_setof.c163
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_decode_short_integer.c68
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_encode_short_integer.c97
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_length_short_integer.c70
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_decode_utctime.c127
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_encode_utctime.c83
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_length_utctime.c46
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_decode_utf8_string.c111
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_encode_utf8_string.c105
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_length_utf8_string.c83
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.c112
-rw-r--r--crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_encode_subject_public_key_info.c83
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_export.c99
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_free.c34
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_import.c101
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_make_key.c125
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_sign_hash.c147
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_hash.c126
-rw-r--r--crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_key.c100
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_i2osp.c51
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_mgf1.c91
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_decode.c192
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_encode.c164
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_os2ip.c36
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_decode.c168
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_encode.c157
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_decode.c110
-rw-r--r--crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_encode.c95
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_decrypt_key.c107
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_encrypt_key.c96
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_export.c87
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_exptmod.c147
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_free.c34
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_import.c128
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_make_key.c105
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_sign_hash.c130
-rw-r--r--crypto/userspace/libtomcrypt/pk/rsa/rsa_verify_hash.c170
-rw-r--r--crypto/userspace/libtommath/LICENSE4
-rw-r--r--crypto/userspace/libtommath/bn_error.c47
-rw-r--r--crypto/userspace/libtommath/bn_fast_mp_invmod.c148
-rw-r--r--crypto/userspace/libtommath/bn_fast_mp_montgomery_reduce.c172
-rw-r--r--crypto/userspace/libtommath/bn_fast_s_mp_mul_digs.c107
-rw-r--r--crypto/userspace/libtommath/bn_fast_s_mp_mul_high_digs.c98
-rw-r--r--crypto/userspace/libtommath/bn_fast_s_mp_sqr.c114
-rw-r--r--crypto/userspace/libtommath/bn_mp_2expt.c48
-rw-r--r--crypto/userspace/libtommath/bn_mp_abs.c43
-rw-r--r--crypto/userspace/libtommath/bn_mp_add.c53
-rw-r--r--crypto/userspace/libtommath/bn_mp_add_d.c112
-rw-r--r--crypto/userspace/libtommath/bn_mp_addmod.c41
-rw-r--r--crypto/userspace/libtommath/bn_mp_clamp.c44
-rw-r--r--crypto/userspace/libtommath/bn_mp_clear.c44
-rw-r--r--crypto/userspace/libtommath/bn_mp_clear_multi.c34
-rw-r--r--crypto/userspace/libtommath/bn_mp_cmp.c43
-rw-r--r--crypto/userspace/libtommath/bn_mp_cmp_d.c44
-rw-r--r--crypto/userspace/libtommath/bn_mp_cmp_mag.c55
-rw-r--r--crypto/userspace/libtommath/bn_mp_cnt_lsb.c53
-rw-r--r--crypto/userspace/libtommath/bn_mp_copy.c68
-rw-r--r--crypto/userspace/libtommath/bn_mp_count_bits.c45
-rw-r--r--crypto/userspace/libtommath/bn_mp_div.c292
-rw-r--r--crypto/userspace/libtommath/bn_mp_div_2.c68
-rw-r--r--crypto/userspace/libtommath/bn_mp_div_2d.c97
-rw-r--r--crypto/userspace/libtommath/bn_mp_div_3.c79
-rw-r--r--crypto/userspace/libtommath/bn_mp_div_d.c115
-rw-r--r--crypto/userspace/libtommath/bn_mp_dr_is_modulus.c43
-rw-r--r--crypto/userspace/libtommath/bn_mp_dr_reduce.c94
-rw-r--r--crypto/userspace/libtommath/bn_mp_dr_setup.c32
-rw-r--r--crypto/userspace/libtommath/bn_mp_exch.c34
-rw-r--r--crypto/userspace/libtommath/bn_mp_expt_d.c57
-rw-r--r--crypto/userspace/libtommath/bn_mp_exptmod.c112
-rw-r--r--crypto/userspace/libtommath/bn_mp_exptmod_fast.c321
-rw-r--r--crypto/userspace/libtommath/bn_mp_gcd.c105
-rw-r--r--crypto/userspace/libtommath/bn_mp_get_int.c45
-rw-r--r--crypto/userspace/libtommath/bn_mp_grow.c57
-rw-r--r--crypto/userspace/libtommath/bn_mp_init.c46
-rw-r--r--crypto/userspace/libtommath/bn_mp_init_copy.c32
-rw-r--r--crypto/userspace/libtommath/bn_mp_init_multi.c59
-rw-r--r--crypto/userspace/libtommath/bn_mp_init_set.c32
-rw-r--r--crypto/userspace/libtommath/bn_mp_init_set_int.c31
-rw-r--r--crypto/userspace/libtommath/bn_mp_init_size.c48
-rw-r--r--crypto/userspace/libtommath/bn_mp_invmod.c43
-rw-r--r--crypto/userspace/libtommath/bn_mp_invmod_slow.c175
-rw-r--r--crypto/userspace/libtommath/bn_mp_is_square.c109
-rw-r--r--crypto/userspace/libtommath/bn_mp_karatsuba_mul.c167
-rw-r--r--crypto/userspace/libtommath/bn_mp_karatsuba_sqr.c121
-rw-r--r--crypto/userspace/libtommath/bn_mp_lcm.c60
-rw-r--r--crypto/userspace/libtommath/bn_mp_lshd.c67
-rw-r--r--crypto/userspace/libtommath/bn_mp_mod.c48
-rw-r--r--crypto/userspace/libtommath/bn_mp_mod_2d.c55
-rw-r--r--crypto/userspace/libtommath/bn_mp_mod_d.c27
-rw-r--r--crypto/userspace/libtommath/bn_mp_montgomery_calc_normalization.c59
-rw-r--r--crypto/userspace/libtommath/bn_mp_montgomery_reduce.c118
-rw-r--r--crypto/userspace/libtommath/bn_mp_montgomery_setup.c59
-rw-r--r--crypto/userspace/libtommath/bn_mp_mul.c66
-rw-r--r--crypto/userspace/libtommath/bn_mp_mul_2.c82
-rw-r--r--crypto/userspace/libtommath/bn_mp_mul_2d.c85
-rw-r--r--crypto/userspace/libtommath/bn_mp_mul_d.c79
-rw-r--r--crypto/userspace/libtommath/bn_mp_mulmod.c40
-rw-r--r--crypto/userspace/libtommath/bn_mp_n_root.c132
-rw-r--r--crypto/userspace/libtommath/bn_mp_neg.c40
-rw-r--r--crypto/userspace/libtommath/bn_mp_prime_is_divisible.c50
-rw-r--r--crypto/userspace/libtommath/bn_mp_prime_is_prime.c83
-rw-r--r--crypto/userspace/libtommath/bn_mp_prime_miller_rabin.c103
-rw-r--r--crypto/userspace/libtommath/bn_mp_prime_next_prime.c170
-rw-r--r--crypto/userspace/libtommath/bn_mp_prime_rabin_miller_trials.c52
-rw-r--r--crypto/userspace/libtommath/bn_mp_prime_random_ex.c125
-rw-r--r--crypto/userspace/libtommath/bn_mp_rand.c55
-rw-r--r--crypto/userspace/libtommath/bn_mp_read_signed_bin.c41
-rw-r--r--crypto/userspace/libtommath/bn_mp_read_unsigned_bin.c55
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce.c100
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_2k.c61
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_2k_l.c62
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_2k_setup.c47
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_2k_setup_l.c44
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_is_2k.c52
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_is_2k_l.c44
-rw-r--r--crypto/userspace/libtommath/bn_mp_reduce_setup.c34
-rw-r--r--crypto/userspace/libtommath/bn_mp_rshd.c72
-rw-r--r--crypto/userspace/libtommath/bn_mp_set.c29
-rw-r--r--crypto/userspace/libtommath/bn_mp_set_int.c48
-rw-r--r--crypto/userspace/libtommath/bn_mp_shrink.c35
-rw-r--r--crypto/userspace/libtommath/bn_mp_signed_bin_size.c27
-rw-r--r--crypto/userspace/libtommath/bn_mp_sqr.c58
-rw-r--r--crypto/userspace/libtommath/bn_mp_sqrmod.c41
-rw-r--r--crypto/userspace/libtommath/bn_mp_sub.c59
-rw-r--r--crypto/userspace/libtommath/bn_mp_sub_d.c93
-rw-r--r--crypto/userspace/libtommath/bn_mp_submod.c42
-rw-r--r--crypto/userspace/libtommath/bn_mp_to_signed_bin.c33
-rw-r--r--crypto/userspace/libtommath/bn_mp_to_signed_bin_n.c31
-rw-r--r--crypto/userspace/libtommath/bn_mp_to_unsigned_bin.c48
-rw-r--r--crypto/userspace/libtommath/bn_mp_to_unsigned_bin_n.c31
-rw-r--r--crypto/userspace/libtommath/bn_mp_toom_mul.c284
-rw-r--r--crypto/userspace/libtommath/bn_mp_toom_sqr.c226
-rw-r--r--crypto/userspace/libtommath/bn_mp_unsigned_bin_size.c28
-rw-r--r--crypto/userspace/libtommath/bn_mp_zero.c36
-rw-r--r--crypto/userspace/libtommath/bn_prime_tab.c61
-rw-r--r--crypto/userspace/libtommath/bn_reverse.c39
-rw-r--r--crypto/userspace/libtommath/bn_s_mp_add.c109
-rw-r--r--crypto/userspace/libtommath/bn_s_mp_exptmod.c252
-rw-r--r--crypto/userspace/libtommath/bn_s_mp_mul_digs.c90
-rw-r--r--crypto/userspace/libtommath/bn_s_mp_mul_high_digs.c81
-rw-r--r--crypto/userspace/libtommath/bn_s_mp_sqr.c84
-rw-r--r--crypto/userspace/libtommath/bn_s_mp_sub.c89
-rw-r--r--crypto/userspace/libtommath/bncore.c36
-rw-r--r--crypto/userspace/libtommath/changes.txt397
-rw-r--r--crypto/userspace/libtommath/pretty.build66
-rw-r--r--crypto/userspace/libtommath/tommath.h569
-rw-r--r--crypto/userspace/libtommath/tommath_class.h999
-rw-r--r--crypto/userspace/libtommath/tommath_superclass.h76
-rw-r--r--crypto/userspace/ncr-dh.c296
-rw-r--r--crypto/userspace/ncr-dh.h27
-rw-r--r--crypto/userspace/ncr-int.h241
-rw-r--r--crypto/userspace/ncr-key-storage.c136
-rw-r--r--crypto/userspace/ncr-key-wrap.c1118
-rw-r--r--crypto/userspace/ncr-key.c832
-rw-r--r--crypto/userspace/ncr-limits.c247
-rw-r--r--crypto/userspace/ncr-pk.c749
-rw-r--r--crypto/userspace/ncr-pk.h64
-rw-r--r--crypto/userspace/ncr-sessions.c1506
-rw-r--r--crypto/userspace/ncr.c519
-rw-r--r--crypto/userspace/utils.c298
-rw-r--r--crypto/userspace/utils.h98
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/audit.h55
-rw-r--r--include/linux/ncr.h287
-rw-r--r--kernel/auditfilter.c2
-rw-r--r--kernel/auditsc.c234
222 files changed, 27482 insertions, 0 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 35cf64d4436..bdca2d758f9 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -201,6 +201,7 @@ Code Seq#(hex) Include File Comments
'c' 00-1F linux/chio.h conflict!
'c' 80-9F arch/s390/include/asm/chsc.h conflict!
'c' A0-AF arch/x86/include/asm/msr.h conflict!
+'c' C0-DF linux/ncr.h conflict!
'd' 00-FF linux/char/drm/drm/h conflict!
'd' 02-40 pcmcia/ds.h conflict!
'd' 10-3F drivers/media/video/dabusb.h conflict!
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 81c185a6971..022768adc23 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -31,6 +31,11 @@ config CRYPTO_FIPS
this is. Note that CRYPTO_ANSI_CPRNG is requred if this
option is selected
+config CRYPTO_USERSPACE
+ tristate "User-space crypto API"
+ help
+ This option provides an user-space API for cryptographic operations.
+
config CRYPTO_ALGAPI
tristate
select CRYPTO_ALGAPI2
diff --git a/crypto/Makefile b/crypto/Makefile
index 9e8f61908cb..bf210884e1f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -90,3 +90,5 @@ obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
#
obj-$(CONFIG_XOR_BLOCKS) += xor.o
obj-$(CONFIG_ASYNC_CORE) += async_tx/
+
+obj-$(CONFIG_CRYPTO_USERSPACE) += userspace/ \ No newline at end of file
diff --git a/crypto/userspace/Makefile b/crypto/userspace/Makefile
new file mode 100644
index 00000000000..7f6d66f8ba5
--- /dev/null
+++ b/crypto/userspace/Makefile
@@ -0,0 +1,70 @@
+ccflags-y += -I$(src)/libtommath -I$(src)/libtomcrypt/headers -I$(src) -DLTC_SOURCE
+
+TOMMATH_OBJECTS = libtommath/bncore.o libtommath/bn_mp_init.o libtommath/bn_mp_clear.o libtommath/bn_mp_exch.o libtommath/bn_mp_grow.o libtommath/bn_mp_shrink.o \
+ libtommath/bn_mp_clamp.o libtommath/bn_mp_zero.o libtommath/bn_mp_set.o libtommath/bn_mp_set_int.o libtommath/bn_mp_init_size.o libtommath/bn_mp_copy.o \
+ libtommath/bn_mp_init_copy.o libtommath/bn_mp_abs.o libtommath/bn_mp_neg.o libtommath/bn_mp_cmp_mag.o libtommath/bn_mp_cmp.o libtommath/bn_mp_cmp_d.o \
+ libtommath/bn_mp_rshd.o libtommath/bn_mp_lshd.o libtommath/bn_mp_mod_2d.o libtommath/bn_mp_div_2d.o libtommath/bn_mp_mul_2d.o libtommath/bn_mp_div_2.o \
+ libtommath/bn_mp_mul_2.o libtommath/bn_s_mp_add.o libtommath/bn_s_mp_sub.o libtommath/bn_fast_s_mp_mul_digs.o libtommath/bn_s_mp_mul_digs.o \
+ libtommath/bn_fast_s_mp_mul_high_digs.o libtommath/bn_s_mp_mul_high_digs.o libtommath/bn_fast_s_mp_sqr.o libtommath/bn_s_mp_sqr.o \
+ libtommath/bn_mp_add.o libtommath/bn_mp_sub.o libtommath/bn_mp_karatsuba_mul.o libtommath/bn_mp_mul.o libtommath/bn_mp_karatsuba_sqr.o \
+ libtommath/bn_mp_sqr.o libtommath/bn_mp_div.o libtommath/bn_mp_mod.o libtommath/bn_mp_add_d.o libtommath/bn_mp_sub_d.o libtommath/bn_mp_mul_d.o \
+ libtommath/bn_mp_div_d.o libtommath/bn_mp_mod_d.o libtommath/bn_mp_expt_d.o libtommath/bn_mp_addmod.o libtommath/bn_mp_submod.o \
+ libtommath/bn_mp_mulmod.o libtommath/bn_mp_sqrmod.o libtommath/bn_mp_gcd.o libtommath/bn_mp_lcm.o libtommath/bn_fast_mp_invmod.o libtommath/bn_mp_invmod.o \
+ libtommath/bn_mp_reduce.o libtommath/bn_mp_montgomery_setup.o libtommath/bn_fast_mp_montgomery_reduce.o libtommath/bn_mp_montgomery_reduce.o \
+ libtommath/bn_mp_exptmod_fast.o libtommath/bn_mp_exptmod.o libtommath/bn_mp_2expt.o libtommath/bn_reverse.o \
+ libtommath/bn_mp_count_bits.o libtommath/bn_mp_read_unsigned_bin.o libtommath/bn_mp_read_signed_bin.o libtommath/bn_mp_to_unsigned_bin.o \
+ libtommath/bn_mp_to_signed_bin.o libtommath/bn_mp_unsigned_bin_size.o libtommath/bn_mp_signed_bin_size.o \
+ libtommath/bn_mp_rand.o libtommath/bn_mp_montgomery_calc_normalization.o \
+ libtommath/bn_mp_prime_is_divisible.o libtommath/bn_prime_tab.o libtommath/bn_mp_prime_miller_rabin.o \
+ libtommath/bn_mp_prime_is_prime.o libtommath/bn_mp_prime_next_prime.o libtommath/bn_mp_dr_reduce.o \
+ libtommath/bn_mp_dr_is_modulus.o libtommath/bn_mp_dr_setup.o libtommath/bn_mp_reduce_setup.o \
+ libtommath/bn_mp_toom_mul.o libtommath/bn_mp_toom_sqr.o libtommath/bn_mp_div_3.o libtommath/bn_s_mp_exptmod.o \
+ libtommath/bn_mp_reduce_2k.o libtommath/bn_mp_reduce_is_2k.o libtommath/bn_mp_reduce_2k_setup.o \
+ libtommath/bn_mp_reduce_2k_l.o libtommath/bn_mp_reduce_is_2k_l.o libtommath/bn_mp_reduce_2k_setup_l.o \
+ libtommath/bn_mp_cnt_lsb.o libtommath/bn_error.o libtommath/bn_mp_init_multi.o libtommath/bn_mp_clear_multi.o \
+ libtommath/bn_mp_prime_random_ex.o libtommath/bn_mp_get_int.o libtommath/bn_mp_init_set.o \
+ libtommath/bn_mp_init_set_int.o libtommath/bn_mp_invmod_slow.o libtommath/bn_mp_prime_rabin_miller_trials.o \
+ libtommath/bn_mp_to_signed_bin_n.o libtommath/bn_mp_to_unsigned_bin_n.o
+
+TOMCRYPT_OBJECTS = libtomcrypt/misc/zeromem.o libtomcrypt/misc/crypt/crypt_argchk.o \
+ libtomcrypt/math/rand_prime.o libtomcrypt/hashes/hash_get_oid.o \
+ libtomcrypt/hashes/crypt_hash_is_valid.o libtomcrypt/hashes/hash_memory.o libtomcrypt/hashes/hash_memory_multi.o \
+ libtomcrypt/pk/dsa/dsa_make_key.o libtomcrypt/pk/dsa/dsa_export.o libtomcrypt/pk/dsa/dsa_import.o \
+ libtomcrypt/pk/dsa/dsa_free.o libtomcrypt/pk/dsa/dsa_sign_hash.o libtomcrypt/pk/dsa/dsa_verify_hash.o \
+ libtomcrypt/pk/dsa/dsa_verify_key.o \
+ libtomcrypt/pk/asn1/der/bit/der_decode_bit_string.o libtomcrypt/pk/asn1/der/bit/der_encode_bit_string.o \
+ libtomcrypt/pk/asn1/der/bit/der_length_bit_string.o libtomcrypt/pk/asn1/der/boolean/der_decode_boolean.o \
+ libtomcrypt/pk/asn1/der/boolean/der_encode_boolean.o libtomcrypt/pk/asn1/der/boolean/der_length_boolean.o \
+ libtomcrypt/pk/asn1/der/choice/der_decode_choice.o libtomcrypt/pk/asn1/der/ia5/der_decode_ia5_string.o \
+ libtomcrypt/pk/asn1/der/ia5/der_encode_ia5_string.o libtomcrypt/pk/asn1/der/ia5/der_length_ia5_string.o \
+ libtomcrypt/pk/asn1/der/integer/der_decode_integer.o libtomcrypt/pk/asn1/der/integer/der_encode_integer.o \
+ libtomcrypt/pk/asn1/der/integer/der_length_integer.o libtomcrypt/pk/asn1/der/object_identifier/der_decode_object_identifier.o \
+ libtomcrypt/pk/asn1/der/object_identifier/der_encode_object_identifier.o libtomcrypt/pk/asn1/der/object_identifier/der_length_object_identifier.o \
+ libtomcrypt/pk/asn1/der/octet/der_decode_octet_string.o libtomcrypt/pk/asn1/der/octet/der_encode_octet_string.o \
+ libtomcrypt/pk/asn1/der/octet/der_length_octet_string.o libtomcrypt/pk/asn1/der/printable_string/der_decode_printable_string.o \
+ libtomcrypt/pk/asn1/der/printable_string/der_encode_printable_string.o libtomcrypt/pk/asn1/der/printable_string/der_length_printable_string.o \
+ libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_ex.o libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_flexi.o \
+ libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_multi.o libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_ex.o \
+ libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_multi.o libtomcrypt/pk/asn1/der/sequence/der_length_sequence.o \
+ libtomcrypt/pk/asn1/der/sequence/der_sequence_free.o libtomcrypt/pk/asn1/der/short_integer/der_decode_short_integer.o \
+ libtomcrypt/pk/asn1/der/short_integer/der_encode_short_integer.o libtomcrypt/pk/asn1/der/short_integer/der_length_short_integer.o \
+ libtomcrypt/pk/asn1/der/utctime/der_decode_utctime.o libtomcrypt/pk/asn1/der/utctime/der_encode_utctime.o \
+ libtomcrypt/pk/asn1/der/utctime/der_length_utctime.o libtomcrypt/pk/asn1/der/utf8/der_decode_utf8_string.o \
+ libtomcrypt/pk/asn1/der/utf8/der_encode_utf8_string.o libtomcrypt/pk/asn1/der/utf8/der_length_utf8_string.o \
+ libtomcrypt/pk/asn1/der/set/der_encode_set.o libtomcrypt/pk/asn1/der/set/der_encode_setof.o \
+ libtomcrypt/pk/rsa/rsa_decrypt_key.o libtomcrypt/pk/rsa/rsa_encrypt_key.o libtomcrypt/pk/rsa/rsa_export.o \
+ libtomcrypt/pk/rsa/rsa_exptmod.o libtomcrypt/pk/rsa/rsa_free.o libtomcrypt/pk/rsa/rsa_import.o \
+ libtomcrypt/pk/rsa/rsa_make_key.o libtomcrypt/pk/rsa/rsa_sign_hash.o libtomcrypt/pk/rsa/rsa_verify_hash.o \
+ libtomcrypt/pk/pkcs1/pkcs_1_i2osp.o libtomcrypt/pk/pkcs1/pkcs_1_mgf1.o libtomcrypt/pk/pkcs1/pkcs_1_oaep_decode.o \
+ libtomcrypt/pk/pkcs1/pkcs_1_oaep_encode.o libtomcrypt/pk/pkcs1/pkcs_1_os2ip.o libtomcrypt/pk/pkcs1/pkcs_1_pss_decode.o \
+ libtomcrypt/pk/pkcs1/pkcs_1_pss_encode.o libtomcrypt/pk/pkcs1/pkcs_1_v1_5_decode.o libtomcrypt/pk/pkcs1/pkcs_1_v1_5_encode.o \
+ libtomcrypt/misc/pk_get_oid.o libtomcrypt/pk/asn1/der/x509/der_encode_subject_public_key_info.o \
+ libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.o
+
+cryptodev-objs := cryptodev_main.o cryptodev_cipher.o ncr.o \
+ ncr-key.o ncr-limits.o ncr-pk.o ncr-sessions.o ncr-dh.o \
+ ncr-key-wrap.o ncr-key-storage.o utils.o $(TOMMATH_OBJECTS) \
+ $(TOMCRYPT_OBJECTS)
+
+
+obj-$(CONFIG_CRYPTO_USERSPACE) += cryptodev.o
diff --git a/crypto/userspace/cryptodev_cipher.c b/crypto/userspace/cryptodev_cipher.c
new file mode 100644
index 00000000000..1fb11473715
--- /dev/null
+++ b/crypto/userspace/cryptodev_cipher.c
@@ -0,0 +1,381 @@
+/*
+ * Driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ * Portions Copyright (c) 2010 Michael Weiser
+ * Portions Copyright (c) 2010 Phil Sutter
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/ioctl.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/uaccess.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include "cryptodev_int.h"
+
+
+struct cryptodev_result {
+ struct completion completion;
+ int err;
+};
+
+static void cryptodev_complete(struct crypto_async_request *req, int err)
+{
+ struct cryptodev_result *res = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ res->err = err;
+ complete(&res->completion);
+}
+
+int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t * keyp, size_t keylen)
+{
+
+ struct ablkcipher_alg* alg;
+ int ret;
+
+ memset(out, 0, sizeof(*out));
+
+ out->async.s = crypto_alloc_ablkcipher(alg_name, 0, 0);
+ if (unlikely(IS_ERR(out->async.s))) {
+ dprintk(1,KERN_DEBUG,"%s: Failed to load cipher %s\n", __func__,
+ alg_name);
+ return -EINVAL;
+ }
+
+ alg = crypto_ablkcipher_alg(out->async.s);
+
+ if (alg != NULL) {
+ /* Was correct key length supplied? */
+ if (alg->max_keysize > 0 && unlikely((keylen < alg->min_keysize) ||
+ (keylen > alg->max_keysize))) {
+ dprintk(1,KERN_DEBUG,"Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.\n",
+ keylen, alg_name, alg->min_keysize,
+ alg->max_keysize);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ ret = crypto_ablkcipher_setkey(out->async.s, keyp, keylen);
+ if (unlikely(ret)) {
+ dprintk(1,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
+ alg_name, keylen*8);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ out->blocksize = crypto_ablkcipher_blocksize(out->async.s);
+ out->ivsize = crypto_ablkcipher_ivsize(out->async.s);
+
+ out->async.result = kmalloc(sizeof(*out->async.result), GFP_KERNEL);
+ if (unlikely(!out->async.result)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memset(out->async.result, 0, sizeof(*out->async.result));
+ init_completion(&out->async.result->completion);
+
+ out->async.request = ablkcipher_request_alloc(out->async.s, GFP_KERNEL);
+ if (unlikely(!out->async.request)) {
+ dprintk(1,KERN_ERR,"error allocating async crypto request\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ablkcipher_request_set_callback(out->async.request, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ cryptodev_complete, out->async.result);
+
+ out->init = 1;
+ return 0;
+error:
+ if (out->async.request)
+ ablkcipher_request_free(out->async.request);
+ kfree(out->async.result);
+ if (out->async.s)
+ crypto_free_ablkcipher(out->async.s);
+
+ return ret;
+}
+
+void cryptodev_cipher_deinit(struct cipher_data* cdata)
+{
+ if (cdata->init) {
+ if (cdata->async.request)
+ ablkcipher_request_free(cdata->async.request);
+ kfree(cdata->async.result);
+ if (cdata->async.s)
+ crypto_free_ablkcipher(cdata->async.s);
+
+ cdata->init = 0;
+ }
+}
+
+void cryptodev_cipher_set_iv(struct cipher_data* cdata, void *iv, size_t iv_size)
+{
+ memcpy(cdata->async.iv, iv, min(iv_size,sizeof(cdata->async.iv)));
+}
+
+static inline int waitfor (struct cryptodev_result* cr, ssize_t ret)
+{
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ wait_for_completion(&cr->completion);
+ /* At this point we known for sure the request has finished,
+ * because wait_for_completion above was not interruptible.
+ * This is important because otherwise hardware or driver
+ * might try to access memory which will be freed or reused for
+ * another request. */
+
+ if (unlikely(cr->err)) {
+ dprintk(0,KERN_ERR,"error from async request: %d \n", cr->err);
+ return cr->err;
+ }
+
+ break;
+ default:
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int _cryptodev_cipher_encrypt(struct cipher_data* cdata, const void* plaintext,
+ size_t plaintext_size, void* ciphertext, size_t ciphertext_size)
+{
+struct scatterlist sg, sg2;
+
+ sg_init_one(&sg, plaintext, plaintext_size);
+ sg_init_one(&sg2, ciphertext, ciphertext_size);
+
+ return cryptodev_cipher_encrypt( cdata, &sg, &sg2, plaintext_size);
+}
+
+int _cryptodev_cipher_decrypt(struct cipher_data* cdata, const void* ciphertext,
+ size_t ciphertext_size, void* plaintext, size_t plaintext_size)
+{
+struct scatterlist sg, sg2;
+
+ sg_init_one(&sg, ciphertext, ciphertext_size);
+ sg_init_one(&sg2, plaintext, plaintext_size);
+
+ return cryptodev_cipher_decrypt( cdata, &sg, &sg2, ciphertext_size);
+}
+
+
+ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len)
+{
+ int ret;
+
+ INIT_COMPLETION(cdata->async.result->completion);
+ ablkcipher_request_set_crypt(cdata->async.request, (struct scatterlist*)sg1, sg2,
+ len, cdata->async.iv);
+ ret = crypto_ablkcipher_encrypt(cdata->async.request);
+
+ return waitfor(cdata->async.result,ret);
+}
+
+ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len)
+{
+ int ret;
+
+ INIT_COMPLETION(cdata->async.result->completion);
+ ablkcipher_request_set_crypt(cdata->async.request, (struct scatterlist*)sg1, sg2,
+ len, cdata->async.iv);
+ ret = crypto_ablkcipher_decrypt(cdata->async.request);
+
+ return waitfor(cdata->async.result, ret);
+}
+
+/* Hash functions */
+
+int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, const void *mackey, size_t mackeylen)
+{
+int ret;
+
+ hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0);
+ if (unlikely(IS_ERR(hdata->async.s))) {
+ dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", __func__,
+ alg_name);
+ return -EINVAL;
+ }
+
+ /* Copy the key from user and set to TFM. */
+ if (mackey != NULL) {
+
+ ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen);
+ if (unlikely(ret)) {
+ dprintk(1,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
+ alg_name, mackeylen*8);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ hdata->digestsize = crypto_ahash_digestsize(hdata->async.s);
+
+ hdata->async.result = kmalloc(sizeof(*hdata->async.result), GFP_KERNEL);
+ if (unlikely(!hdata->async.result)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memset(hdata->async.result, 0, sizeof(*hdata->async.result));
+ init_completion(&hdata->async.result->completion);
+
+ hdata->async.request = ahash_request_alloc(hdata->async.s, GFP_KERNEL);
+ if (unlikely(!hdata->async.request)) {
+ dprintk(0,KERN_ERR,"error allocating async crypto request\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ahash_request_set_callback(hdata->async.request, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ cryptodev_complete, hdata->async.result);
+
+ ret = crypto_ahash_init(hdata->async.request);
+ if (unlikely(ret)) {
+ dprintk(0,KERN_ERR,
+ "error in crypto_hash_init()\n");
+ goto error_request;
+ }
+
+ hdata->init = 1;
+ return 0;
+
+error_request:
+ ahash_request_free(hdata->async.request);
+error:
+ kfree(hdata->async.result);
+ crypto_free_ahash(hdata->async.s);
+ return ret;
+}
+
+int cryptodev_hash_clone(struct hash_data *hdata, struct hash_data *old_data,
+ const void *mackey, size_t mackeylen)
+{
+ const char *algo;
+ void *state;
+ int ret;
+
+ /* We want exactly the same driver. */
+ algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(old_data->async.s));
+ ret = cryptodev_hash_init(hdata, algo, mackey, mackeylen);
+ if (unlikely(ret != 0))
+ return ret;
+
+ state = kmalloc(crypto_ahash_statesize(hdata->async.s), GFP_KERNEL);
+ if (unlikely(state == NULL)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = crypto_ahash_export(old_data->async.request, state);
+ if (unlikely(ret != 0)) {
+ dprintk(0, KERN_ERR, "error exporting hash state\n");
+ goto err;
+ }
+ ret = crypto_ahash_import(hdata->async.request, state);
+ if (unlikely(ret != 0)) {
+ dprintk(0,KERN_ERR,
+ "error in crypto_hash_init()\n");
+ goto err;
+ }
+
+ kfree(state);
+
+ hdata->init = 1;
+ return 0;
+
+err:
+ kfree(state);
+ cryptodev_hash_deinit(hdata);
+ return ret;
+}
+
+void cryptodev_hash_deinit(struct hash_data* hdata)
+{
+ if (hdata->init) {
+ if (hdata->async.request)
+ ahash_request_free(hdata->async.request);
+ kfree(hdata->async.result);
+ if (hdata->async.s)
+ crypto_free_ahash(hdata->async.s);
+ hdata->init = 0;
+ }
+}
+
+int cryptodev_hash_reset( struct hash_data* hdata)
+{
+int ret;
+ ret = crypto_ahash_init(hdata->async.request);
+ if (unlikely(ret)) {
+ dprintk(0,KERN_ERR,
+ "error in crypto_hash_init()\n");
+ return ret;
+ }
+
+ return 0;
+
+}
+
+ssize_t cryptodev_hash_update( struct hash_data* hdata, struct scatterlist *sg, size_t len)
+{
+ int ret;
+
+ INIT_COMPLETION(hdata->async.result->completion);
+ ahash_request_set_crypt(hdata->async.request, sg, NULL,
+ len);
+
+ ret = crypto_ahash_update(hdata->async.request);
+
+ return waitfor(hdata->async.result,ret);
+}
+
+ssize_t _cryptodev_hash_update( struct hash_data* hdata, const void* data, size_t len)
+{
+struct scatterlist sg;
+
+ sg_init_one(&sg, data, len);
+
+ return cryptodev_hash_update( hdata, &sg, len);
+}
+
+int cryptodev_hash_final( struct hash_data* hdata, void* output)
+{
+ int ret;
+
+ INIT_COMPLETION(hdata->async.result->completion);
+ ahash_request_set_crypt(hdata->async.request, NULL, output, 0);
+
+ ret = crypto_ahash_final(hdata->async.request);
+
+ return waitfor(hdata->async.result,ret);
+}
diff --git a/crypto/userspace/cryptodev_int.h b/crypto/userspace/cryptodev_int.h
new file mode 100644
index 00000000000..ce705be363a
--- /dev/null
+++ b/crypto/userspace/cryptodev_int.h
@@ -0,0 +1,84 @@
+/* cipher stuff */
+#ifndef CRYPTODEV_INT_H
+# define CRYPTODEV_INT_H
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ncr.h>
+#include <linux/scatterlist.h>
+
+#define PFX "cryptodev: "
+#define dprintk(level,severity,format,a...) \
+ do { \
+ if (level <= cryptodev_verbosity) \
+ printk(severity PFX "%s[%u]: " format, \
+ current->comm, current->pid, \
+ ##a); \
+ } while (0)
+
+extern int cryptodev_verbosity;
+
+/* For zero copy */
+int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
+ int pgcount, struct page **pg, struct scatterlist *sg);
+void release_user_pages(struct page **pg, int pagecount);
+
+/* last page - first page + 1 */
+#define PAGECOUNT(buf, buflen) \
+ ((((unsigned long)(buf + buflen - 1) & PAGE_MASK) >> PAGE_SHIFT) - \
+ (((unsigned long) buf & PAGE_MASK) >> PAGE_SHIFT) + 1)
+
+#define DEFAULT_PREALLOC_PAGES 32
+
+struct cipher_data
+{
+ int init; /* 0 uninitialized */
+ int blocksize;
+ int ivsize;
+ struct {
+ struct crypto_ablkcipher* s;
+ struct cryptodev_result *result;
+ struct ablkcipher_request *request;
+ uint8_t iv[NCR_CIPHER_MAX_BLOCK_LEN];
+ } async;
+};
+
+int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t * key, size_t keylen);
+void cryptodev_cipher_deinit(struct cipher_data* cdata);
+ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len);
+ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len);
+
+void cryptodev_cipher_set_iv(struct cipher_data* cdata, void* iv, size_t iv_size);
+int _cryptodev_cipher_decrypt(struct cipher_data* cdata, const void* ciphertext,
+ size_t ciphertext_size, void* plaintext, size_t plaintext_size);
+int _cryptodev_cipher_encrypt(struct cipher_data* cdata, const void* plaintext,
+ size_t plaintext_size, void* ciphertext, size_t ciphertext_size);
+
+/* hash stuff */
+struct hash_data
+{
+ int init; /* 0 uninitialized */
+ int digestsize;
+ struct {
+ struct crypto_ahash *s;
+ struct cryptodev_result *result;
+ struct ahash_request *request;
+ } async;
+};
+
+int cryptodev_hash_final( struct hash_data* hdata, void* output);
+ssize_t cryptodev_hash_update( struct hash_data* hdata, struct scatterlist *sg, size_t len);
+ssize_t _cryptodev_hash_update( struct hash_data* hdata, const void* data, size_t len);
+int cryptodev_hash_reset( struct hash_data* hdata);
+void cryptodev_hash_deinit(struct hash_data* hdata);
+int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, const void *mackey, size_t mackeylen);
+int cryptodev_hash_clone(struct hash_data *hdata, struct hash_data *old_data,
+ const void *mackey, size_t mackeylen);
+
+#endif /* CRYPTODEV_INT_H */
diff --git a/crypto/userspace/cryptodev_main.c b/crypto/userspace/cryptodev_main.c
new file mode 100644
index 00000000000..89cd15b6287
--- /dev/null
+++ b/crypto/userspace/cryptodev_main.c
@@ -0,0 +1,229 @@
+/*
+ * Driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2004 Michal Ludvig <mludvig@logix.net.nz>, SuSE Labs
+ * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Device /dev/crypto provides an interface for
+ * accessing kernel CryptoAPI algorithms (ciphers,
+ * hashes) from userspace programs.
+ *
+ * /dev/crypto interface was originally introduced in
+ * OpenBSD and this module attempts to keep the API.
+ *
+ */
+
+#include <linux/audit.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/ioctl.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include "cryptodev_int.h"
+#include "ncr-int.h"
+#include <linux/version.h>
+
+MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
+MODULE_DESCRIPTION("CryptoDev driver");
+MODULE_LICENSE("GPL");
+
+/* ====== Module parameters ====== */
+
+int cryptodev_verbosity = 0;
+module_param(cryptodev_verbosity, int, 0644);
+MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
+
+/* ====== CryptoAPI ====== */
+
+void release_user_pages(struct page **pg, int pagecount)
+{
+ while (pagecount--) {
+ if (!PageReserved(pg[pagecount]))
+ SetPageDirty(pg[pagecount]);
+ page_cache_release(pg[pagecount]);
+ }
+}
+
+/* offset of buf in it's first page */
+#define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK)
+
+/* fetch the pages addr resides in into pg and initialise sg with them */
+int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
+ int pgcount, struct page **pg, struct scatterlist *sg)
+{
+ int ret, pglen, i = 0;
+ struct scatterlist *sgp;
+
+ down_write(&current->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm,
+ (unsigned long)addr, pgcount, write, 0, pg, NULL);
+ up_write(&current->mm->mmap_sem);
+ if (ret != pgcount)
+ return -EINVAL;
+
+ sg_init_table(sg, pgcount);
+
+ pglen = min((ptrdiff_t)(PAGE_SIZE - PAGEOFFSET(addr)), (ptrdiff_t)len);
+ sg_set_page(sg, pg[i++], pglen, PAGEOFFSET(addr));
+
+ len -= pglen;
+ for (sgp = sg_next(sg); len; sgp = sg_next(sgp)) {
+ pglen = min((uint32_t)PAGE_SIZE, len);
+ sg_set_page(sgp, pg[i++], pglen, 0);
+ len -= pglen;
+ }
+ sg_mark_end(sg_last(sg, pgcount));
+ return 0;
+}
+
+/* ====== /dev/crypto ====== */
+
+static int
+cryptodev_open(struct inode *inode, struct file *filp)
+{
+ struct ncr_lists *ncr;
+ int ret;
+
+ ncr = ncr_init_lists();
+ if (ncr == NULL) {
+ return -ENOMEM;
+ }
+
+ ret = audit_log_crypto_op(AUDIT_CRYPTO_OP_CONTEXT_NEW, ncr->id, -1,
+ NULL, NULL, -1, NULL, 0, -1, NULL, 0);
+ if (ret < 0) {
+ ncr_deinit_lists(ncr);
+ return ret;
+ }
+
+ filp->private_data = ncr;
+ return 0;
+}
+
+static int
+cryptodev_release(struct inode *inode, struct file *filp)
+{
+ struct ncr_lists *ncr = filp->private_data;
+
+ if (ncr) {
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_CONTEXT_DEL, ncr->id, -1,
+ NULL, NULL, -1, NULL, 0, -1, NULL, 0);
+ ncr_deinit_lists(ncr);
+ filp->private_data = NULL;
+ }
+
+ return 0;
+}
+
+static long
+cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ void *ncr = filp->private_data;
+
+ if (unlikely(!ncr))
+ BUG();
+
+ return ncr_ioctl(ncr, cmd, arg);
+}
+
+/* compatibility code for 32bit userlands */
+#ifdef CONFIG_COMPAT
+
+static long
+cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void *ncr = file->private_data;
+
+ if (unlikely(!ncr))
+ BUG();
+
+ return ncr_compat_ioctl(ncr, cmd, arg);
+}
+
+#endif /* CONFIG_COMPAT */
+
+static const struct file_operations cryptodev_fops = {
+ .owner = THIS_MODULE,
+ .open = cryptodev_open,
+ .release = cryptodev_release,
+ .unlocked_ioctl = cryptodev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = cryptodev_compat_ioctl,
+#endif /* CONFIG_COMPAT */
+};
+
+static struct miscdevice cryptodev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "crypto",
+ .fops = &cryptodev_fops,
+};
+
+static int __init
+cryptodev_register(void)
+{
+ int rc;
+
+ ncr_limits_init();
+ ncr_master_key_reset();
+
+ rc = misc_register (&cryptodev);
+ if (unlikely(rc)) {
+ ncr_limits_deinit();
+ printk(KERN_ERR PFX "registration of /dev/crypto failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static void __exit
+cryptodev_deregister(void)
+{
+ misc_deregister(&cryptodev);
+ ncr_limits_deinit();
+}
+
+/* ====== Module init/exit ====== */
+static int __init init_cryptodev(void)
+{
+ int rc;
+
+ rc = cryptodev_register();
+ if (unlikely(rc))
+ return rc;
+
+ printk(KERN_INFO PFX "driver loaded.\n");
+
+ return 0;
+}
+
+static void __exit exit_cryptodev(void)
+{
+ cryptodev_deregister();
+ printk(KERN_INFO PFX "driver unloaded.\n");
+}
+
+module_init(init_cryptodev);
+module_exit(exit_cryptodev);
diff --git a/crypto/userspace/libtomcrypt/hashes/crypt_hash_is_valid.c b/crypto/userspace/libtomcrypt/hashes/crypt_hash_is_valid.c
new file mode 100644
index 00000000000..d01d4183f80
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/hashes/crypt_hash_is_valid.c
@@ -0,0 +1,30 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file crypt_hash_is_valid.c
+ Determine if hash is valid, Tom St Denis
+*/
+
+/*
+ Test if a hash index is valid
+ @param idx The hash to search for
+ @return CRYPT_OK if valid
+*/
+int hash_is_valid(const struct algo_properties_st *hash)
+{
+ return CRYPT_OK;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/hashes/hash_get_oid.c b/crypto/userspace/libtomcrypt/hashes/hash_get_oid.c
new file mode 100644
index 00000000000..39f43722884
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/hashes/hash_get_oid.c
@@ -0,0 +1,78 @@
+/* LibTomCrypt, modular cryptographic library
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+/*
+ Returns the OID of the hash.
+ @param idx The hash identifier of the hash to search for
+ @return CRYPT_OK if valid
+*/
+
+static const oid_st sha1_oid = {
+ .OIDlen = 6,
+ .OID = { 1, 3, 14, 3, 2, 26 },
+};
+
+static const oid_st md5_oid = {
+ .OIDlen = 6,
+ .OID = { 1, 2, 840, 113549, 2, 5, },
+};
+
+static const oid_st sha224_oid = {
+ .OIDlen = 9,
+ .OID = { 2, 16, 840, 1, 101, 3, 4, 2, 4, },
+};
+
+static const oid_st sha256_oid = {
+ .OIDlen = 9,
+ .OID = { 2, 16, 840, 1, 101, 3, 4, 2, 1, },
+};
+
+static const oid_st sha384_oid = {
+ .OIDlen = 9,
+ .OID = { 2, 16, 840, 1, 101, 3, 4, 2, 2, },
+};
+
+static const oid_st sha512_oid = {
+ .OIDlen = 9,
+ .OID = { 2, 16, 840, 1, 101, 3, 4, 2, 3, },
+};
+
+int hash_get_oid(const struct algo_properties_st *hash, oid_st *st)
+{
+ switch (hash->algo) {
+ case NCR_ALG_SHA1:
+ memcpy(st, &sha1_oid, sizeof(*st));
+ break;
+ case NCR_ALG_MD5:
+ memcpy(st, &md5_oid, sizeof(*st));
+ break;
+ case NCR_ALG_SHA2_224:
+ memcpy(st, &sha224_oid, sizeof(*st));
+ break;
+ case NCR_ALG_SHA2_256:
+ memcpy(st, &sha256_oid, sizeof(*st));
+ break;
+ case NCR_ALG_SHA2_384:
+ memcpy(st, &sha384_oid, sizeof(*st));
+ break;
+ case NCR_ALG_SHA2_512:
+ memcpy(st, &sha512_oid, sizeof(*st));
+ break;
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+ return CRYPT_OK;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/hashes/hash_memory.c b/crypto/userspace/libtomcrypt/hashes/hash_memory.c
new file mode 100644
index 00000000000..c6f51881245
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/hashes/hash_memory.c
@@ -0,0 +1,66 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+#include <cryptodev_int.h>
+
+/**
+ @file hash_memory.c
+ Hash memory helper, Tom St Denis
+*/
+
+/**
+ Hash a block of memory and store the digest.
+ @param hash The hash you wish to use
+ @param in The data you wish to hash
+ @param inlen The length of the data to hash (octets)
+ @param out [out] Where to store the digest
+ @param outlen [in/out] Max size and resulting size of the digest
+ @return CRYPT_OK if successful
+*/
+int hash_memory(const struct algo_properties_st *hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
+{
+ int err;
+ struct hash_data hdata;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (*outlen < hash->digest_size) {
+ *outlen = hash->digest_size;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ err = cryptodev_hash_init(&hdata, hash->kstr, NULL, 0);
+ if (err < 0) {
+ err = CRYPT_INVALID_HASH;
+ goto LBL_ERR;
+ }
+
+ if ((err = _cryptodev_hash_update(&hdata, in, inlen)) < 0) {
+ err = CRYPT_ERROR;
+ goto LBL_ERR;
+ }
+
+ err = cryptodev_hash_final(&hdata, out);
+
+ *outlen = hash->digest_size;
+LBL_ERR:
+ cryptodev_hash_deinit(&hdata);
+
+ return err;
+}
+
diff --git a/crypto/userspace/libtomcrypt/hashes/hash_memory_multi.c b/crypto/userspace/libtomcrypt/hashes/hash_memory_multi.c
new file mode 100644
index 00000000000..74226767a72
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/hashes/hash_memory_multi.c
@@ -0,0 +1,84 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+#include <ncr-int.h>
+#include <cryptodev_int.h>
+
+/**
+ @file hash_memory_multi.c
+ Hash (multiple buffers) memory helper, Tom St Denis
+*/
+
+/**
+ Hash multiple (non-adjacent) blocks of memory at once.
+ @param hash The hash you wish to use
+ @param out [out] Where to store the digest
+ @param outlen [in/out] Max size and resulting size of the digest
+ @param in The data you wish to hash
+ @param inlen The length of the data to hash (octets)
+ @param ... tuples of (data,len) pairs to hash, terminated with a (NULL,x) (x=don't care)
+ @return CRYPT_OK if successful
+*/
+int hash_memory_multi(const struct algo_properties_st *hash, unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...)
+{
+ struct hash_data hdata;
+ int err;
+ va_list args;
+ const unsigned char *curptr;
+ unsigned long curlen;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (*outlen < hash->digest_size) {
+ *outlen = hash->digest_size;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ err = cryptodev_hash_init(&hdata, hash->kstr, NULL, 0);
+ if (err < 0) {
+ err = CRYPT_INVALID_HASH;
+ goto LBL_ERR;
+ }
+
+ va_start(args, inlen);
+ curptr = in;
+ curlen = inlen;
+ for (;;) {
+ /* process buf */
+ if ((err = _cryptodev_hash_update(&hdata, curptr, curlen)) < 0) {
+ err = CRYPT_ERROR;
+ goto LBL_ERR;
+ }
+ /* step to next */
+ curptr = va_arg(args, const unsigned char*);
+ if (curptr == NULL) {
+ break;
+ }
+ curlen = va_arg(args, unsigned long);
+ }
+
+ err = cryptodev_hash_final(&hdata, out);
+
+ *outlen = hash->digest_size;
+LBL_ERR:
+ cryptodev_hash_deinit(&hdata);
+ va_end(args);
+ return err;
+}
+
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt.h b/crypto/userspace/libtomcrypt/headers/tomcrypt.h
new file mode 100644
index 00000000000..a9c675d0944
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt.h
@@ -0,0 +1,84 @@
+#ifndef TOMCRYPT_H_
+#define TOMCRYPT_H_
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/nls.h>
+#include <linux/sort.h>
+
+/* use configuration data */
+#include <tomcrypt_custom.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* version */
+#define CRYPT 0x0117
+#define SCRYPT "1.17"
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE 128
+
+/* descriptor table size */
+#define TAB_SIZE 32
+
+/* error codes [will be expanded in future releases] */
+enum {
+ CRYPT_OK=0, /* Result OK */
+ CRYPT_ERROR, /* Generic Error */
+ CRYPT_NOP, /* Not a failure but no operation was performed */
+
+ CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
+ CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
+ CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
+
+ CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
+ CRYPT_INVALID_PACKET, /* Invalid input packet given */
+
+ CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
+ CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
+
+ CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
+ CRYPT_INVALID_HASH, /* Invalid hash specified */
+ CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
+
+ CRYPT_MEM, /* Out of memory */
+
+ CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
+ CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
+
+ CRYPT_INVALID_ARG, /* Generic invalid argument */
+ CRYPT_FILE_NOTFOUND, /* File Not Found */
+
+ CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
+ CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */
+ CRYPT_PK_DUP, /* Duplicate key already in key ring */
+ CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
+ CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
+
+ CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */
+ CRYPT_PK_INVALID_PADDING /* Invalid padding on input */
+};
+
+#include <tomcrypt_cfg.h>
+#include <tomcrypt_macros.h>
+#include <tomcrypt_math.h>
+#include <tomcrypt_pk.h>
+#include <tomcrypt_hash.h>
+#include <tomcrypt_misc.h>
+#include <tomcrypt_argchk.h>
+#include <tomcrypt_pkcs.h>
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* TOMCRYPT_H_ */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt.h,v $ */
+/* $Revision: 1.21 $ */
+/* $Date: 2006/12/16 19:34:05 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_argchk.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_argchk.h
new file mode 100644
index 00000000000..1ba08c7ffad
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_argchk.h
@@ -0,0 +1,36 @@
+/* Defines the LTC_ARGCHK macro used within the library */
+/* ARGTYPE is defined in mycrypt_cfg.h */
+#if ARGTYPE == 0
+
+/* this is the default LibTomCrypt macro */
+void crypt_argchk(char *v, char *s, int d);
+#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 1
+
+/* fatal type of error */
+#define LTC_ARGCHK(x) assert((x))
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 2
+
+#define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 3
+
+#define LTC_ARGCHK(x)
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 4
+
+#define LTC_ARGCHK(x) if (!(x)) { printk( "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); return CRYPT_INVALID_ARG; }
+#define LTC_ARGCHKVD(x) if (!(x)) { printk( "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); return; }
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_argchk.h,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/08/27 20:50:21 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_cfg.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_cfg.h
new file mode 100644
index 00000000000..93db10e6729
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_cfg.h
@@ -0,0 +1,135 @@
+/* This is the build config file.
+ *
+ * With this you can setup what to inlcude/exclude automatically during any build. Just comment
+ * out the line that #define's the word for the thing you want to remove. phew!
+ */
+
+#ifndef TOMCRYPT_CFG_H
+#define TOMCRYPT_CFG_H
+
+#if defined(_WIN32) || defined(_MSC_VER)
+#define LTC_CALL __cdecl
+#else
+#ifndef LTC_CALL
+ #define LTC_CALL
+#endif
+#endif
+
+#ifndef LTC_EXPORT
+#define LTC_EXPORT
+#endif
+
+/* certain platforms use macros for these, making the prototypes broken */
+#ifndef LTC_NO_PROTOTYPES
+
+LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
+
+/* you can change how memory allocation works ... */
+LTC_EXPORT void * LTC_CALL XMALLOC(size_t n);
+LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n);
+LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s);
+LTC_EXPORT void LTC_CALL XFREE(void *p);
+
+/* change the clock function too */
+LTC_EXPORT clock_t LTC_CALL XCLOCK(void);
+
+/* various other functions */
+LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n);
+LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n);
+LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n);
+
+LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2);
+
+#endif
+
+/* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing, 4=return error */
+#ifndef ARGTYPE
+ #define ARGTYPE 4
+#endif
+
+/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code
+ *
+ * Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes.
+ * The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST**
+ * use the portable [slower] macros.
+ */
+
+/* detect x86-32 machines somewhat */
+#if !defined(__STRICT_ANSI__) && (defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__))))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_32BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detects MIPS R5900 processors (PS2) */
+#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_64BITWORD
+#endif
+
+/* detect amd64 */
+#if !defined(__STRICT_ANSI__) && defined(__x86_64__)
+ #define ENDIAN_LITTLE
+ #define ENDIAN_64BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detect PPC32 */
+#if !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+ #define ENDIAN_BIG
+ #define ENDIAN_32BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detect sparc and sparc64 */
+#if defined(__sparc__)
+ #define ENDIAN_BIG
+ #if defined(__arch64__)
+ #define ENDIAN_64BITWORD
+ #else
+ #define ENDIAN_32BITWORD
+ #endif
+#endif
+
+
+#ifdef LTC_NO_FAST
+ #ifdef LTC_FAST
+ #undef LTC_FAST
+ #endif
+#endif
+
+/* No asm is a quick way to disable anything "not portable" */
+#ifdef LTC_NO_ASM
+ #undef ENDIAN_LITTLE
+ #undef ENDIAN_BIG
+ #undef ENDIAN_32BITWORD
+ #undef ENDIAN_64BITWORD
+ #undef LTC_FAST
+ #undef LTC_FAST_TYPE
+ #define LTC_NO_ROLC
+ #define LTC_NO_BSWAP
+#endif
+
+/* #define ENDIAN_LITTLE */
+/* #define ENDIAN_BIG */
+
+/* #define ENDIAN_32BITWORD */
+/* #define ENDIAN_64BITWORD */
+
+#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
+ #error You must specify a word size as well as endianess in tomcrypt_cfg.h
+#endif
+
+#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
+ #define ENDIAN_NEUTRAL
+#endif
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cfg.h,v $ */
+/* $Revision: 1.19 $ */
+/* $Date: 2006/12/04 02:19:48 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_custom.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_custom.h
new file mode 100644
index 00000000000..76b574487bc
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_custom.h
@@ -0,0 +1,408 @@
+#ifndef TOMCRYPT_CUSTOM_H_
+#define TOMCRYPT_CUSTOM_H_
+
+#define LTC_NO_PROTOTYPES
+
+/* macros for various libc functions you can change for embedded targets */
+#ifndef XMALLOC
+ #ifdef malloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMALLOC(x) kmalloc(x, GFP_KERNEL)
+#endif
+#ifndef XREALLOC
+ #ifdef realloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XREALLOC(x,y) krealloc(x,y,GFP_KERNEL)
+#endif
+#ifndef XCALLOC
+ #ifdef calloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XCALLOC(x,y) kcalloc(x, y, GFP_KERNEL)
+#endif
+#ifndef XFREE
+ #ifdef free
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XFREE kfree
+#endif
+
+#ifndef XMEMSET
+ #ifdef memset
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMSET memset
+#endif
+#ifndef XMEMCPY
+ #ifdef memcpy
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMCPY memcpy
+#endif
+#ifndef XMEMCMP
+ #ifdef memcmp
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMCMP memcmp
+#endif
+#ifndef XSTRCMP
+ #ifdef strcmp
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XSTRCMP strcmp
+#endif
+
+#ifndef XCLOCK
+#define XCLOCK clock
+#endif
+#ifndef XCLOCKS_PER_SEC
+#define XCLOCKS_PER_SEC CLOCKS_PER_SEC
+#endif
+
+#ifndef XQSORT
+ #ifdef qsort
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XQSORT(x,y,z,w) sort(x,y,z,w,NULL)
+#endif
+
+/* Easy button? */
+#ifdef LTC_EASY
+ #define LTC_NO_CIPHERS
+ #define LTC_RIJNDAEL
+ #define LTC_BLOWFISH
+ #define LTC_DES
+ #define LTC_CAST5
+
+ #define LTC_NO_MODES
+ #define LTC_ECB_MODE
+ #define LTC_CBC_MODE
+ #define LTC_CTR_MODE
+
+ #define LTC_NO_HASHES
+ #define LTC_SHA1
+ #define LTC_SHA512
+ #define LTC_SHA384
+ #define LTC_SHA256
+ #define LTC_SHA224
+
+ #define LTC_NO_MACS
+ #define LTC_HMAC
+ #define LTC_OMAC
+ #define LTC_CCM_MODE
+
+ #define LTC_NO_PRNGS
+ #define LTC_SPRNG
+ #define LTC_YARROW
+ #define LTC_DEVRANDOM
+ #define TRY_URANDOM_FIRST
+
+ #define LTC_NO_PK
+ #define LTC_MRSA
+ #define LTC_MECC
+#endif
+
+/* Use small code where possible */
+/* #define LTC_SMALL_CODE */
+
+/* Enable self-test test vector checking */
+#ifndef LTC_NO_TEST
+ #define LTC_TEST
+#endif
+
+/* clean the stack of functions which put private information on stack */
+/* #define LTC_CLEAN_STACK */
+
+/* disable all file related functions */
+/* #define LTC_NO_FILE */
+
+/* disable all forms of ASM */
+/* #define LTC_NO_ASM */
+
+/* disable FAST mode */
+/* #define LTC_NO_FAST */
+
+/* disable BSWAP on x86 */
+/* #define LTC_NO_BSWAP */
+
+/* ---> Symmetric Block Ciphers <--- */
+#ifndef LTC_NO_CIPHERS
+
+#define LTC_BLOWFISH
+#define LTC_RC2
+#define LTC_RC5
+#define LTC_RC6
+#define LTC_SAFERP
+#define LTC_RIJNDAEL
+#define LTC_XTEA
+/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
+ * (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
+#define LTC_TWOFISH
+#ifndef LTC_NO_TABLES
+ #define LTC_TWOFISH_TABLES
+ /* #define LTC_TWOFISH_ALL_TABLES */
+#else
+ #define LTC_TWOFISH_SMALL
+#endif
+/* #define LTC_TWOFISH_SMALL */
+/* LTC_DES includes EDE triple-LTC_DES */
+#define LTC_DES
+#define LTC_CAST5
+#define LTC_NOEKEON
+#define LTC_SKIPJACK
+#define LTC_SAFER
+#define LTC_KHAZAD
+#define LTC_ANUBIS
+#define LTC_ANUBIS_TWEAK
+#define LTC_KSEED
+#define LTC_KASUMI
+
+#endif /* LTC_NO_CIPHERS */
+
+
+/* ---> Block Cipher Modes of Operation <--- */
+#ifndef LTC_NO_MODES
+
+#define LTC_CFB_MODE
+#define LTC_OFB_MODE
+#define LTC_ECB_MODE
+#define LTC_CBC_MODE
+#define LTC_CTR_MODE
+
+/* F8 chaining mode */
+#define LTC_F8_MODE
+
+/* LRW mode */
+#define LTC_LRW_MODE
+#ifndef LTC_NO_TABLES
+ /* like GCM mode this will enable 16 8x128 tables [64KB] that make
+ * seeking very fast.
+ */
+ #define LRW_TABLES
+#endif
+
+/* XTS mode */
+#define LTC_XTS_MODE
+
+#endif /* LTC_NO_MODES */
+
+/* ---> One-Way Hash Functions <--- */
+#ifndef LTC_NO_HASHES
+
+#define LTC_CHC_HASH
+#define LTC_WHIRLPOOL
+#define LTC_SHA512
+#define LTC_SHA384
+#define LTC_SHA256
+#define LTC_SHA224
+#define LTC_TIGER
+#define LTC_SHA1
+#define LTC_MD5
+#define LTC_MD4
+#define LTC_MD2
+#define LTC_RIPEMD128
+#define LTC_RIPEMD160
+#define LTC_RIPEMD256
+#define LTC_RIPEMD320
+
+#endif /* LTC_NO_HASHES */
+
+/* ---> MAC functions <--- */
+#ifndef LTC_NO_MACS
+
+#define LTC_HMAC
+#define LTC_OMAC
+#define LTC_PMAC
+#define LTC_XCBC
+#define LTC_F9_MODE
+#define LTC_PELICAN
+
+#if defined(LTC_PELICAN) && !defined(LTC_RIJNDAEL)
+ #error Pelican-MAC requires LTC_RIJNDAEL
+#endif
+
+/* ---> Encrypt + Authenticate Modes <--- */
+
+#define LTC_EAX_MODE
+#if defined(LTC_EAX_MODE) && !(defined(LTC_CTR_MODE) && defined(LTC_OMAC))
+ #error LTC_EAX_MODE requires CTR and LTC_OMAC mode
+#endif
+
+#define LTC_OCB_MODE
+#define LTC_CCM_MODE
+#define LTC_GCM_MODE
+
+/* Use 64KiB tables */
+#ifndef LTC_NO_TABLES
+ #define LTC_GCM_TABLES
+#endif
+
+/* USE SSE2? requires GCC works on x86_32 and x86_64*/
+#ifdef LTC_GCM_TABLES
+/* #define LTC_GCM_TABLES_SSE2 */
+#endif
+
+#endif /* LTC_NO_MACS */
+
+/* Various tidbits of modern neatoness */
+#define LTC_BASE64
+
+/* --> Pseudo Random Number Generators <--- */
+#ifndef LTC_NO_PRNGS
+
+/* Yarrow */
+#define LTC_YARROW
+/* which descriptor of AES to use? */
+/* 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] */
+#define LTC_YARROW_AES 0
+
+#if defined(LTC_YARROW) && !defined(LTC_CTR_MODE)
+ #error LTC_YARROW requires LTC_CTR_MODE chaining mode to be defined!
+#endif
+
+/* a PRNG that simply reads from an available system source */
+#define LTC_SPRNG
+
+/* The LTC_RC4 stream cipher */
+#define LTC_RC4
+
+/* Fortuna PRNG */
+#define LTC_FORTUNA
+/* reseed every N calls to the read function */
+#define LTC_FORTUNA_WD 10
+/* number of pools (4..32) can save a bit of ram by lowering the count */
+#define LTC_FORTUNA_POOLS 32
+
+/* Greg's LTC_SOBER128 PRNG ;-0 */
+#define LTC_SOBER128
+
+/* the *nix style /dev/random device */
+#define LTC_DEVRANDOM
+/* try /dev/urandom before trying /dev/random */
+#define TRY_URANDOM_FIRST
+
+#endif /* LTC_NO_PRNGS */
+
+/* ---> math provider? <--- */
+#ifndef LTC_NO_MATH
+
+/* LibTomMath */
+#define LTM_LTC_DESC
+
+/* TomsFastMath */
+/* #define TFM_LTC_DESC */
+
+#endif /* LTC_NO_MATH */
+
+/* ---> Public Key Crypto <--- */
+#ifndef LTC_NO_PK
+
+/* Include RSA support */
+#define LTC_MRSA
+
+/* Include Katja (a Rabin variant like RSA) */
+/* #define MKAT */
+
+/* Digital Signature Algorithm */
+#define LTC_MDSA
+
+/* ECC */
+#define LTC_MECC
+
+/* use Shamir's trick for point mul (speeds up signature verification) */
+#define LTC_ECC_SHAMIR
+
+#if defined(TFM_LTC_DESC) && defined(LTC_MECC)
+ #define LTC_MECC_ACCEL
+#endif
+
+/* do we want fixed point ECC */
+/* #define LTC_MECC_FP */
+
+/* Timing Resistant? */
+/* #define LTC_ECC_TIMING_RESISTANT */
+
+#endif /* LTC_NO_PK */
+
+/* LTC_PKCS #1 (RSA) and #5 (Password Handling) stuff */
+#ifndef LTC_NO_PKCS
+
+#define LTC_PKCS_1
+#define LTC_PKCS_5
+
+/* Include ASN.1 DER (required by DSA/RSA) */
+#define LTC_DER
+
+#endif /* LTC_NO_PKCS */
+
+/* cleanup */
+
+#ifdef LTC_MECC
+/* Supported ECC Key Sizes */
+#ifndef LTC_NO_CURVES
+ #define ECC112
+ #define ECC128
+ #define ECC160
+ #define ECC192
+ #define ECC224
+ #define ECC256
+ #define ECC384
+ #define ECC521
+#endif
+#endif
+
+#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(MKATJA)
+ /* Include the MPI functionality? (required by the PK algorithms) */
+ #define MPI
+#endif
+
+#ifdef LTC_MRSA
+ #define LTC_PKCS_1
+#endif
+
+#if defined(LTC_DER) && !defined(MPI)
+ #error ASN.1 DER requires MPI functionality
+#endif
+
+#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC) || defined(MKATJA)) && !defined(LTC_DER)
+ #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
+#endif
+
+/* THREAD management */
+#ifdef LTC_PTHREAD
+
+#include <pthread.h>
+
+#define LTC_MUTEX_GLOBAL(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
+#define LTC_MUTEX_PROTO(x) extern pthread_mutex_t x;
+#define LTC_MUTEX_TYPE(x) pthread_mutex_t x;
+#define LTC_MUTEX_INIT(x) pthread_mutex_init(x, NULL);
+#define LTC_MUTEX_LOCK(x) pthread_mutex_lock(x);
+#define LTC_MUTEX_UNLOCK(x) pthread_mutex_unlock(x);
+
+#else
+
+/* default no functions */
+#define LTC_MUTEX_GLOBAL(x)
+#define LTC_MUTEX_PROTO(x)
+#define LTC_MUTEX_TYPE(x)
+#define LTC_MUTEX_INIT(x)
+#define LTC_MUTEX_LOCK(x)
+#define LTC_MUTEX_UNLOCK(x)
+
+#endif
+
+/* Debuggers */
+
+/* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and LTC_RC4 work (see the code) */
+/* #define LTC_VALGRIND */
+
+#endif
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_custom.h,v $ */
+/* $Revision: 1.73 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_hash.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_hash.h
new file mode 100644
index 00000000000..e4e84e4841b
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_hash.h
@@ -0,0 +1,14 @@
+/* ---- HASH FUNCTIONS ---- */
+
+struct algo_properties_st;
+
+int hash_is_valid(const struct algo_properties_st *hash);
+
+int hash_memory(const struct algo_properties_st *hash,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int hash_memory_multi(const struct algo_properties_st *hash, unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+
+int hash_get_oid(const struct algo_properties_st *hash, oid_st* st);
+
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_macros.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_macros.h
new file mode 100644
index 00000000000..53bda9bb4ba
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_macros.h
@@ -0,0 +1,424 @@
+/* fix for MSVC ...evil! */
+#ifdef _MSC_VER
+ #define CONST64(n) n ## ui64
+ typedef unsigned __int64 ulong64;
+#else
+ #define CONST64(n) n ## ULL
+ typedef unsigned long long ulong64;
+#endif
+
+/* this is the "32-bit at least" data type
+ * Re-define it to suit your platform but it must be at least 32-bits
+ */
+#if defined(__x86_64__) || (defined(__sparc__) && defined(__arch64__))
+ typedef unsigned ulong32;
+#else
+ typedef unsigned long ulong32;
+#endif
+
+/* ---- HELPER MACROS ---- */
+#ifdef ENDIAN_NEUTRAL
+
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif /* ENDIAN_NEUTRAL */
+
+#ifdef ENDIAN_LITTLE
+
+#if !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__))))
+
+#define STORE32H(x, y) \
+asm __volatile__ ( \
+ "bswapl %0 \n\t" \
+ "movl %0,(%1)\n\t" \
+ "bswapl %0 \n\t" \
+ ::"r"(x), "r"(y));
+
+#define LOAD32H(x, y) \
+asm __volatile__ ( \
+ "movl (%1),%0\n\t" \
+ "bswapl %0\n\t" \
+ :"=r"(x): "r"(y));
+
+#else
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#endif
+
+
+/* x86_64 processor */
+#if !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__))
+
+#define STORE64H(x, y) \
+asm __volatile__ ( \
+ "bswapq %0 \n\t" \
+ "movq %0,(%1)\n\t" \
+ "bswapq %0 \n\t" \
+ ::"r"(x), "r"(y));
+
+#define LOAD64H(x, y) \
+asm __volatile__ ( \
+ "movq (%1),%0\n\t" \
+ "bswapq %0\n\t" \
+ :"=r"(x): "r"(y));
+
+#else
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32L(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ XMEMCPY(&(x), y, 4);
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32L(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y) \
+ { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64L(x, y) \
+ { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+
+#endif /* ENDIAN_LITTLE */
+
+#ifdef ENDIAN_BIG
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32H(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ XMEMCPY(&(x), y, 4);
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+ (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32H(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y) \
+ { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64H(x, y) \
+ { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
+ ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
+
+
+/* 32-bit Rotates */
+#if defined(_MSC_VER)
+
+/* instrinsic rotate */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+ asm ("roll %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+ asm ("rorl %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+ asm ("roll %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+ asm ("rorl %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+ asm ("rotlw %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"r" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+ asm ("rotlw %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"r" (32-i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+ asm ("rotlwi %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+ asm ("rotrwi %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+
+#else
+
+/* rotates the hard way */
+#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#endif
+
+
+/* 64-bit Rotates */
+#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(LTC_NO_ASM)
+
+static inline unsigned long ROL64(unsigned long word, int i)
+{
+ asm("rolq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned long ROR64(unsigned long word, int i)
+{
+ asm("rorq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned long ROL64c(unsigned long word, const int i)
+{
+ asm("rolq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+static inline unsigned long ROR64c(unsigned long word, const int i)
+{
+ asm("rorq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+#else /* LTC_NO_ROLC */
+
+#define ROL64c ROL64
+#define ROR64c ROR64
+
+#endif
+
+#else /* Not x86_64 */
+
+#define ROL64(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#endif
+
+#ifndef MAX
+ #define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#endif
+
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* extract a byte portably */
+#ifdef _MSC_VER
+ #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+ #define byte(x, n) (((x) >> (8 * (n))) & 255)
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_macros.h,v $ */
+/* $Revision: 1.15 $ */
+/* $Date: 2006/11/29 23:43:57 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_math.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_math.h
new file mode 100644
index 00000000000..6c0e6c5fb34
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_math.h
@@ -0,0 +1,13 @@
+/** math functions **/
+
+#define LTC_MP_LT -1
+#define LTC_MP_EQ 0
+#define LTC_MP_GT 1
+
+#define LTC_MP_NO 0
+#define LTC_MP_YES 1
+
+#include <tommath.h>
+
+typedef mp_int* mp_int_t;
+
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_misc.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_misc.h
new file mode 100644
index 00000000000..f5384cacc51
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_misc.h
@@ -0,0 +1,23 @@
+/* ---- LTC_BASE64 Routines ---- */
+#ifdef LTC_BASE64
+int base64_encode(const unsigned char *in, unsigned long len,
+ unsigned char *out, unsigned long *outlen);
+
+int base64_decode(const unsigned char *in, unsigned long len,
+ unsigned char *out, unsigned long *outlen);
+#endif
+
+/* ---- MEM routines ---- */
+void zeromem(void *dst, size_t len);
+void burn_stack(unsigned long len);
+
+const char *error_to_string(int err);
+
+extern const char *crypt_build_settings;
+
+/* ---- HMM ---- */
+int crypt_fsa(void *mp, ...);
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_misc.h,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_pk.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_pk.h
new file mode 100644
index 00000000000..73348805748
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_pk.h
@@ -0,0 +1,359 @@
+/* ---- NUMBER THEORY ---- */
+
+struct algo_properties_st;
+
+enum {
+ PK_PUBLIC=0,
+ PK_PRIVATE=1
+};
+
+enum {
+ PKA_RSA,
+ PKA_DSA
+};
+
+typedef struct Oid {
+ unsigned long OID[16];
+ /** Length of DER encoding */
+ unsigned long OIDlen;
+} oid_st;
+
+int pk_get_oid(int pk, oid_st *st);
+int rand_prime(mp_int *N, long len);
+
+/* ---- RSA ---- */
+#ifdef LTC_MRSA
+
+/* Min and Max RSA key sizes (in bits) */
+#define MIN_RSA_SIZE 1024
+#define MAX_RSA_SIZE 8192
+
+/** RSA LTC_PKCS style key */
+typedef struct Rsa_key {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** The public exponent */
+ mp_int e;
+ /** The private exponent */
+ mp_int d;
+ /** The modulus */
+ mp_int N;
+ /** The p factor of N */
+ mp_int p;
+ /** The q factor of N */
+ mp_int q;
+ /** The 1/q mod p CRT param */
+ mp_int qP;
+ /** The d mod (p - 1) CRT param */
+ mp_int dP;
+ /** The d mod (q - 1) CRT param */
+ mp_int dQ;
+} rsa_key;
+
+int rsa_make_key(int size, long e, rsa_key *key);
+
+int rsa_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key);
+
+void rsa_free(rsa_key *key);
+
+/* These use LTC_PKCS #1 v2.0 padding */
+#define rsa_encrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash, _key) \
+ rsa_encrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash, LTC_LTC_PKCS_1_OAEP, _key)
+
+#define rsa_decrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash, _stat, _key) \
+ rsa_decrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash, LTC_LTC_PKCS_1_OAEP, _stat, _key)
+
+#define rsa_sign_hash(_in, _inlen, _out, _outlen, _hash, _saltlen, _key) \
+ rsa_sign_hash_ex(_in, _inlen, _out, _outlen, LTC_LTC_PKCS_1_PSS, _hash, _saltlen, _key)
+
+#define rsa_verify_hash(_sig, _siglen, _hash, _hashlen, _hash_algo, _saltlen, _stat, _key) \
+ rsa_verify_hash_ex(_sig, _siglen, _hash, _hashlen, LTC_LTC_PKCS_1_PSS, _hash_algo, _saltlen, _stat, _key)
+
+/* These can be switched between LTC_PKCS #1 v2.x and LTC_PKCS #1 v1.5 paddings */
+int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ const struct algo_properties_st *hash, int padding, rsa_key *key);
+
+int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ const struct algo_properties_st *hash, int padding,
+ int *stat, rsa_key *key);
+
+int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ int padding,
+ const struct algo_properties_st *hash, unsigned long saltlen,
+ rsa_key *key);
+
+int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int padding,
+ const struct algo_properties_st *hash_algo, unsigned long saltlen,
+ int *stat, rsa_key *key);
+
+/* LTC_PKCS #1 import/export */
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key);
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key);
+
+#endif
+
+
+#ifdef LTC_MDSA
+
+/* Max diff between group and modulus size in bytes */
+#define LTC_MDSA_DELTA 512
+
+/* Max DSA group size in bytes (default allows 4k-bit groups) */
+#define LTC_MDSA_MAX_GROUP 512
+
+/** DSA key structure */
+typedef struct {
+ /** The key type, PK_PRIVATE or PK_PUBLIC */
+ int type;
+
+ /** The order of the sub-group used in octets */
+ int qord;
+
+ /** The generator */
+ mp_int g;
+
+ /** The prime used to generate the sub-group */
+ mp_int q;
+
+ /** The large prime that generats the field the contains the sub-group */
+ mp_int p;
+
+ /** The private key */
+ mp_int x;
+
+ /** The public key */
+ mp_int y;
+} dsa_key;
+
+int dsa_make_key(int group_size, int modulus_size, dsa_key *key);
+void dsa_free(dsa_key *key);
+
+int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen,
+ mp_int_t r, mp_int_t s,
+ dsa_key *key);
+
+int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ dsa_key *key);
+
+int dsa_verify_hash_raw( mp_int_t r, mp_int_t s,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key);
+
+int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key);
+
+int dsa_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ int hash, dsa_key *key);
+
+int dsa_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ dsa_key *key);
+
+int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key);
+int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key);
+int dsa_verify_key(dsa_key *key, int *stat);
+
+int dsa_shared_secret(void *private_key, mp_int_t base,
+ dsa_key *public_key,
+ unsigned char *out, unsigned long *outlen);
+#endif
+
+#ifdef LTC_DER
+/* DER handling */
+
+enum {
+ LTC_ASN1_EOL,
+ LTC_ASN1_BOOLEAN,
+ LTC_ASN1_INTEGER,
+ LTC_ASN1_SHORT_INTEGER,
+ LTC_ASN1_BIT_STRING,
+ LTC_ASN1_OCTET_STRING,
+ LTC_ASN1_NULL,
+ LTC_ASN1_OBJECT_IDENTIFIER,
+ LTC_ASN1_IA5_STRING,
+ LTC_ASN1_PRINTABLE_STRING,
+ LTC_ASN1_UTF8_STRING,
+ LTC_ASN1_UTCTIME,
+ LTC_ASN1_CHOICE,
+ LTC_ASN1_SEQUENCE,
+ LTC_ASN1_SET,
+ LTC_ASN1_SETOF
+};
+
+/** A LTC ASN.1 list type */
+typedef struct ltc_asn1_list_ {
+ /** The LTC ASN.1 enumerated type identifier */
+ int type;
+ /** The data to encode or place for decoding */
+ void *data;
+ /** The size of the input or resulting output */
+ unsigned long size;
+ /** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
+ int used;
+ /** prev/next entry in the list */
+ struct ltc_asn1_list_ *prev, *next, *child, *parent;
+} ltc_asn1_list;
+
+#define LTC_SET_ASN1(list, index, Type, Data, Size) \
+ do { \
+ int LTC_MACRO_temp = (index); \
+ ltc_asn1_list *LTC_MACRO_list = (list); \
+ LTC_MACRO_list[LTC_MACRO_temp].type = (Type); \
+ LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data); \
+ LTC_MACRO_list[LTC_MACRO_temp].size = (Size); \
+ LTC_MACRO_list[LTC_MACRO_temp].used = 0; \
+ } while (0);
+
+/* SEQUENCE */
+int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int type_of);
+
+#define der_encode_sequence(list, inlen, out, outlen) der_encode_sequence_ex(list, inlen, out, outlen, LTC_ASN1_SEQUENCE)
+
+int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *list, unsigned long outlen, int ordered);
+
+#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 1)
+
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+ unsigned long *outlen);
+
+/* SUBJECT PUBLIC KEY INFO */
+int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
+ unsigned int algorithm, void* public_key, unsigned long public_key_len,
+ unsigned long parameters_type, void* parameters, unsigned long parameters_len);
+
+int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
+ unsigned int algorithm, void* public_key, unsigned long* public_key_len,
+ unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len);
+
+/* SET */
+#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 0)
+#define der_length_set der_length_sequence
+int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+/* VA list handy helpers with triplets of <type, size, data> */
+int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
+
+/* FLEXI DECODER handle unknown list decoder */
+int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out);
+void der_free_sequence_flexi(ltc_asn1_list *list);
+void der_sequence_free(ltc_asn1_list *in);
+
+/* BOOLEAN */
+int der_length_boolean(unsigned long *outlen);
+int der_encode_boolean(int in,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+ int *out);
+/* INTEGER */
+int der_encode_integer(mp_int_t num, unsigned char *out, unsigned long *outlen);
+int der_decode_integer(const unsigned char *in, unsigned long inlen, mp_int_t num);
+int der_length_integer(mp_int_t num, unsigned long *len);
+
+/* INTEGER -- handy for 0..2^32-1 values */
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num);
+int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen);
+int der_length_short_integer(unsigned long num, unsigned long *outlen);
+
+/* BIT STRING */
+int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen);
+
+/* OCTET STRING */
+int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen);
+
+/* OBJECT IDENTIFIER */
+int der_encode_object_identifier(unsigned long *words, unsigned long nwords,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
+ unsigned long *words, unsigned long *outlen);
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen);
+unsigned long der_object_identifier_bits(unsigned long x);
+
+/* IA5 STRING */
+int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_ia5_char_encode(int c);
+int der_ia5_value_decode(int v);
+
+/* Printable STRING */
+int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_printable_char_encode(int c);
+int der_printable_value_decode(int v);
+
+/* UTF-8 */
+
+int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
+ wchar_t *out, unsigned long *outlen);
+unsigned long der_utf8_charsize(const wchar_t c);
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen);
+
+
+/* CHOICE */
+int der_decode_choice(const unsigned char *in, unsigned long *inlen,
+ ltc_asn1_list *list, unsigned long outlen);
+
+/* UTCTime */
+typedef struct {
+ unsigned YY, /* year */
+ MM, /* month */
+ DD, /* day */
+ hh, /* hour */
+ mm, /* minute */
+ ss, /* second */
+ off_dir, /* timezone offset direction 0 == +, 1 == - */
+ off_hh, /* timezone offset hours */
+ off_mm; /* timezone offset minutes */
+} ltc_utctime;
+
+int der_encode_utctime(ltc_utctime *utctime,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+ ltc_utctime *out);
+
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen);
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pk.h,v $ */
+/* $Revision: 1.81 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_pkcs.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_pkcs.h
new file mode 100644
index 00000000000..be0d7f6822a
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_pkcs.h
@@ -0,0 +1,67 @@
+/* LTC_PKCS Header Info */
+
+/* ===> LTC_PKCS #1 -- RSA Cryptography <=== */
+#ifdef LTC_PKCS_1
+
+struct algo_properties_st;
+
+enum ltc_pkcs_1_v1_5_blocks
+{
+ LTC_LTC_PKCS_1_EMSA = 1, /* Block type 1 (LTC_PKCS #1 v1.5 signature padding) */
+ LTC_LTC_PKCS_1_EME = 2 /* Block type 2 (LTC_PKCS #1 v1.5 encryption padding) */
+};
+
+enum ltc_pkcs_1_paddings
+{
+ LTC_LTC_PKCS_1_V1_5 = 1, /* LTC_PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */
+ LTC_LTC_PKCS_1_OAEP = 2, /* LTC_PKCS #1 v2.0 encryption padding */
+ LTC_LTC_PKCS_1_PSS = 3 /* LTC_PKCS #1 v2.1 signature padding */
+};
+
+int pkcs_1_mgf1(const struct algo_properties_st *hash,
+ const unsigned char *seed, unsigned long seedlen,
+ unsigned char *mask, unsigned long masklen);
+
+int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
+int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
+
+/* *** v1.5 padding */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen);
+
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen,
+ int *is_valid);
+
+/* *** v2.1 padding */
+int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, const struct algo_properties_st *hash,
+ unsigned char *out, unsigned long *outlen);
+
+int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, const struct algo_properties_st *hash,
+ unsigned char *out, unsigned long *outlen,
+ int *res);
+
+int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
+ unsigned long saltlen, const struct algo_properties_st *hash,
+ unsigned long modulus_bitlen,
+ unsigned char *out, unsigned long *outlen);
+
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+ const unsigned char *sig, unsigned long siglen,
+ unsigned long saltlen, const struct algo_properties_st *hash,
+ unsigned long modulus_bitlen, int *res);
+
+#endif /* LTC_PKCS_1 */
+
diff --git a/crypto/userspace/libtomcrypt/headers/tomcrypt_prng.h b/crypto/userspace/libtomcrypt/headers/tomcrypt_prng.h
new file mode 100644
index 00000000000..26bf711e3ce
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/headers/tomcrypt_prng.h
@@ -0,0 +1,80 @@
+/* ---- PRNG Stuff ---- */
+
+typedef union Prng_state {
+ char dummy[1];
+} prng_state;
+
+/** PRNG descriptor */
+extern struct ltc_prng_descriptor {
+ /** Name of the PRNG */
+ char *name;
+ /** size in bytes of exported state */
+ int export_size;
+ /** Start a PRNG state
+ @param prng [out] The state to initialize
+ @return CRYPT_OK if successful
+ */
+ int (*start)(prng_state *prng);
+ /** Add entropy to the PRNG
+ @param in The entropy
+ @param inlen Length of the entropy (octets)\
+ @param prng The PRNG state
+ @return CRYPT_OK if successful
+ */
+ int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+ /** Ready a PRNG state to read from
+ @param prng The PRNG state to ready
+ @return CRYPT_OK if successful
+ */
+ int (*ready)(prng_state *prng);
+ /** Read from the PRNG
+ @param out [out] Where to store the data
+ @param outlen Length of data desired (octets)
+ @param prng The PRNG state to read from
+ @return Number of octets read
+ */
+ unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng);
+ /** Terminate a PRNG state
+ @param prng The PRNG state to terminate
+ @return CRYPT_OK if successful
+ */
+ int (*done)(prng_state *prng);
+ /** Export a PRNG state
+ @param out [out] The destination for the state
+ @param outlen [in/out] The max size and resulting size of the PRNG state
+ @param prng The PRNG to export
+ @return CRYPT_OK if successful
+ */
+ int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng);
+ /** Import a PRNG state
+ @param in The data to import
+ @param inlen The length of the data to import (octets)
+ @param prng The PRNG to initialize/import
+ @return CRYPT_OK if successful
+ */
+ int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+ /** Self-test the PRNG
+ @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+ */
+ int (*test)(void);
+} prng_descriptor[];
+
+int linux_start(prng_state *prng);
+int linux_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int linux_ready(prng_state *prng);
+unsigned long linux_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int linux_done(prng_state *prng);
+int linux_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int linux_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int linux_test(void);
+
+extern const struct ltc_prng_descriptor linux_desc;
+
+int find_prng(const char *name);
+int register_prng(const struct ltc_prng_descriptor *prng);
+int unregister_prng(const struct ltc_prng_descriptor *prng);
+int prng_is_valid(int idx);
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_prng.h,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/math/rand_prime.c b/crypto/userspace/libtomcrypt/math/rand_prime.c
new file mode 100644
index 00000000000..5eff3a188ca
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/math/rand_prime.c
@@ -0,0 +1,80 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file rand_prime.c
+ Generate a random prime, Tom St Denis
+*/
+
+#define USE_BBS 1
+
+int rand_prime(mp_int *N, long len)
+{
+ int err, res, type;
+ unsigned char *buf;
+
+ LTC_ARGCHK(N != NULL);
+
+ /* get type */
+ if (len < 0) {
+ type = USE_BBS;
+ len = -len;
+ } else {
+ type = 0;
+ }
+
+ /* allow sizes between 2 and 512 bytes for a prime size */
+ if (len < 2 || len > 512) {
+ return CRYPT_INVALID_PRIME_SIZE;
+ }
+
+ /* allocate buffer to work with */
+ buf = XCALLOC(1, len);
+ if (buf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ do {
+ /* generate value */
+ get_random_bytes( buf, len);
+
+ /* munge bits */
+ buf[0] |= 0x80 | 0x40;
+ buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
+
+ /* load value */
+ if ((err = mp_read_unsigned_bin(N, buf, len)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+
+ /* test */
+ if ((err = mp_prime_is_prime(N, 8, &res)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+ } while (res == LTC_MP_NO);
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, len);
+#endif
+
+ XFREE(buf);
+ return CRYPT_OK;
+}
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/math/rand_prime.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:23 $ */
diff --git a/crypto/userspace/libtomcrypt/misc/crypt/crypt_argchk.c b/crypto/userspace/libtomcrypt/misc/crypt/crypt_argchk.c
new file mode 100644
index 00000000000..143b784359d
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/misc/crypt/crypt_argchk.c
@@ -0,0 +1,28 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file crypt_argchk.c
+ Perform argument checking, Tom St Denis
+*/
+
+#if (ARGTYPE == 0)
+void crypt_argchk(char *v, char *s, int d)
+{
+ printk("LTC_ARGCHK '%s' failure on line %d of file %s\n",
+ v, d, s);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_argchk.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/misc/pk_get_oid.c b/crypto/userspace/libtomcrypt/misc/pk_get_oid.c
new file mode 100644
index 00000000000..197d7aea20d
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/misc/pk_get_oid.c
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ */
+#include "tomcrypt.h"
+
+static const oid_st rsa_oid = {
+ .OIDlen = 7,
+ .OID = { 1, 2, 840, 113549, 1, 1, 1 },
+};
+
+static const oid_st dsa_oid = {
+ .OIDlen = 6,
+ .OID = { 1, 2, 840, 10040, 4, 1 },
+};
+
+/*
+ Returns the OID of the public key algorithm.
+ @return CRYPT_OK if valid
+*/
+int pk_get_oid(int pk, oid_st *st)
+{
+ switch (pk) {
+ case PKA_RSA:
+ memcpy(st, &rsa_oid, sizeof(*st));
+ break;
+ case PKA_DSA:
+ memcpy(st, &dsa_oid, sizeof(*st));
+ break;
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+ return CRYPT_OK;
+}
+
diff --git a/crypto/userspace/libtomcrypt/misc/zeromem.c b/crypto/userspace/libtomcrypt/misc/zeromem.c
new file mode 100644
index 00000000000..a4bb124fdc6
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/misc/zeromem.c
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file zeromem.c
+ Zero a block of memory, Tom St Denis
+*/
+
+/**
+ Zero a block of memory
+ @param out The destination of the area to zero
+ @param outlen The length of the area to zero (octets)
+*/
+void zeromem(void *out, size_t outlen)
+{
+ unsigned char *mem = out;
+ LTC_ARGCHKVD(out != NULL);
+ while (outlen-- > 0) {
+ *mem++ = 0;
+ }
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/zeromem.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_decode_bit_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_decode_bit_string.c
new file mode 100644
index 00000000000..c9f6368e0ff
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_decode_bit_string.c
@@ -0,0 +1,106 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_bit_string.c
+ ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+#define setbit(v, n) (v=((unsigned char)(v) | (1U << (unsigned char)(n))))
+
+/**
+ Store a BIT STRING
+ @param in The DER encoded BIT STRING
+ @param inlen The size of the DER BIT STRING
+ @param out [out] The array of bits stored (8 per char)
+ @param outlen [in/out] The number of bits stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long dlen, blen, x, y;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* packet must be at least 4 bytes */
+ if (inlen < 4) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* check for 0x03 */
+ if ((in[0]&0x1F) != 0x03) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* offset in the data */
+ x = 1;
+
+ /* get the length of the data */
+ if (in[x] & 0x80) {
+ /* long format get number of length bytes */
+ y = in[x++] & 0x7F;
+
+ /* invalid if 0 or > 2 */
+ if (y == 0 || y > 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data len */
+ dlen = 0;
+ while (y--) {
+ dlen = (dlen << 8) | (unsigned long)in[x++];
+ }
+ } else {
+ /* short format */
+ dlen = in[x++] & 0x7F;
+ }
+
+ /* is the data len too long or too short? */
+ if ((dlen == 0) || (dlen + x > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* get padding count */
+ blen = ((dlen - 1) << 3) - (in[x++] & 7);
+
+ /* too many bits? */
+ if (blen > *outlen) {
+ *outlen = blen;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* decode/store the bits */
+ for (y = 0; y < blen; y++) {
+ if (in[x] & (1 << (7 - (y & 7)))) {
+ setbit(out[y/8], 7-(y%8));
+ }
+ if ((y & 7) == 7) {
+ ++x;
+ }
+ }
+
+ /* we done */
+ *outlen = blen;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/bit/der_decode_bit_string.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_encode_bit_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_encode_bit_string.c
new file mode 100644
index 00000000000..d1b6064a86c
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_encode_bit_string.c
@@ -0,0 +1,92 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_bit_string.c
+ ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+#define getbit(n, k) (((n) & ( 1 << (k) )) >> (k))
+
+/**
+ Store a BIT STRING
+ @param in The array of bits to store (8 per char)
+ @param inlen The number of bits tostore
+ @param out [out] The destination for the DER encoded BIT STRING
+ @param outlen [in/out] The max size and resulting size of the DER BIT STRING
+ @return CRYPT_OK if successful
+*/
+int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long len, x, y;
+ unsigned char buf;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* avoid overflows */
+ if ((err = der_length_bit_string(inlen, &len)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* store header (include bit padding count in length) */
+ x = 0;
+ y = (inlen >> 3) + ((inlen&7) ? 1 : 0) + 1;
+
+ out[x++] = 0x03;
+ if (y < 128) {
+ out[x++] = (unsigned char)y;
+ } else if (y < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)y;
+ } else if (y < 65536) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((y>>8)&255);
+ out[x++] = (unsigned char)(y&255);
+ }
+
+ /* store number of zero padding bits */
+ out[x++] = (unsigned char)((8 - inlen) & 7);
+
+ /* store the bits in big endian format */
+ for (y = buf = 0; y < inlen; y++) {
+ buf |= (getbit(in[y/8],7-y%8)?1:0) << (7 - (y & 7));
+ if ((y & 7) == 7) {
+ out[x++] = buf;
+ buf = 0;
+ }
+ }
+ /* store last byte */
+ if (inlen & 7) {
+ out[x++] = buf;
+ }
+
+ *outlen = x;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/bit/der_encode_bit_string.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_length_bit_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_length_bit_string.c
new file mode 100644
index 00000000000..3b7a8e14e4f
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/bit/der_length_bit_string.c
@@ -0,0 +1,54 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_bit_string.c
+ ASN.1 DER, get length of BIT STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of BIT STRING
+ @param nbits The number of bits in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen)
+{
+ unsigned long nbytes;
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get the number of the bytes */
+ nbytes = (nbits >> 3) + ((nbits & 7) ? 1 : 0) + 1;
+
+ if (nbytes < 128) {
+ /* 03 LL PP DD DD DD ... */
+ *outlen = 2 + nbytes;
+ } else if (nbytes < 256) {
+ /* 03 81 LL PP DD DD DD ... */
+ *outlen = 3 + nbytes;
+ } else if (nbytes < 65536) {
+ /* 03 82 LL LL PP DD DD DD ... */
+ *outlen = 4 + nbytes;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/bit/der_length_bit_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_decode_boolean.c b/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_decode_boolean.c
new file mode 100644
index 00000000000..f374aa6920a
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_decode_boolean.c
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_boolean.c
+ ASN.1 DER, decode a BOOLEAN, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Read a BOOLEAN
+ @param in The destination for the DER encoded BOOLEAN
+ @param inlen The size of the DER BOOLEAN
+ @param out [out] The boolean to decode
+ @return CRYPT_OK if successful
+*/
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+ int *out)
+{
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (inlen != 3 || in[0] != 0x01 || in[1] != 0x01 || (in[2] != 0x00 && in[2] != 0xFF)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *out = (in[2]==0xFF) ? 1 : 0;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/boolean/der_decode_boolean.c,v $ */
+/* $Revision: 1.2 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_encode_boolean.c b/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_encode_boolean.c
new file mode 100644
index 00000000000..df497bfb7e6
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_encode_boolean.c
@@ -0,0 +1,51 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_boolean.c
+ ASN.1 DER, encode a BOOLEAN, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a BOOLEAN
+ @param in The boolean to encode
+ @param out [out] The destination for the DER encoded BOOLEAN
+ @param outlen [in/out] The max size and resulting size of the DER BOOLEAN
+ @return CRYPT_OK if successful
+*/
+int der_encode_boolean(int in,
+ unsigned char *out, unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (*outlen < 3) {
+ *outlen = 3;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ *outlen = 3;
+ out[0] = 0x01;
+ out[1] = 0x01;
+ out[2] = in ? 0xFF : 0x00;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/boolean/der_encode_boolean.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_length_boolean.c b/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_length_boolean.c
new file mode 100644
index 00000000000..aa3e03d764e
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/boolean/der_length_boolean.c
@@ -0,0 +1,35 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_boolean.c
+ ASN.1 DER, get length of a BOOLEAN, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of a BOOLEAN
+ @param outlen [out] The length of the DER encoding
+ @return CRYPT_OK if successful
+*/
+int der_length_boolean(unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+ *outlen = 3;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/boolean/der_length_boolean.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/choice/der_decode_choice.c b/crypto/userspace/libtomcrypt/pk/asn1/der/choice/der_decode_choice.c
new file mode 100644
index 00000000000..277c731b093
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/choice/der_decode_choice.c
@@ -0,0 +1,182 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_choice.c
+ ASN.1 DER, decode a CHOICE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a CHOICE
+ @param in The DER encoded input
+ @param inlen [in/out] The size of the input and resulting size of read type
+ @param list The list of items to decode
+ @param outlen The number of items in the list
+ @return CRYPT_OK on success
+*/
+int der_decode_choice(const unsigned char *in, unsigned long *inlen,
+ ltc_asn1_list *list, unsigned long outlen)
+{
+ unsigned long size, x, z;
+ void *data;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+ LTC_ARGCHK(list != NULL);
+
+ /* get blk size */
+ if (*inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* set all of the "used" flags to zero */
+ for (x = 0; x < outlen; x++) {
+ list[x].used = 0;
+ }
+
+ /* now scan until we have a winner */
+ for (x = 0; x < outlen; x++) {
+ size = list[x].size;
+ data = list[x].data;
+
+ switch (list[x].type) {
+ case LTC_ASN1_INTEGER:
+ if (der_decode_integer(in, *inlen, data) == CRYPT_OK) {
+ if (der_length_integer(data, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ if (der_decode_short_integer(in, *inlen, data) == CRYPT_OK) {
+ if (der_length_short_integer(size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ if (der_decode_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_bit_string(size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ if (der_decode_octet_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_octet_string(size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_NULL:
+ if (*inlen == 2 && in[x] == 0x05 && in[x+1] == 0x00) {
+ *inlen = 2;
+ list[x].used = 1;
+ return CRYPT_OK;
+ }
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ if (der_decode_object_identifier(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_object_identifier(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ if (der_decode_ia5_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_ia5_string(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ if (der_decode_printable_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_printable_string(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ if (der_decode_utf8_string(in, *inlen, data, &size) == CRYPT_OK) {
+ if (der_length_utf8_string(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ list[x].size = size;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = *inlen;
+ if (der_decode_utctime(in, &z, data) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ break;
+
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ if (der_decode_sequence(in, *inlen, data, size) == CRYPT_OK) {
+ if (der_length_sequence(data, size, &z) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ return CRYPT_INVALID_PACKET;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/choice/der_decode_choice.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_decode_ia5_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_decode_ia5_string.c
new file mode 100644
index 00000000000..001477b6ffb
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_decode_ia5_string.c
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_ia5_string.c
+ ASN.1 DER, encode a IA5 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a IA5 STRING
+ @param in The DER encoded IA5 STRING
+ @param inlen The size of the DER IA5 STRING
+ @param out [out] The array of octets stored (one per char)
+ @param outlen [in/out] The number of octets stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int t;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x16 */
+ if ((in[0] & 0x1F) != 0x16) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ /* is it too long? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data */
+ for (y = 0; y < len; y++) {
+ t = der_ia5_value_decode(in[x++]);
+ if (t == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ out[y] = t;
+ }
+
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/ia5/der_decode_ia5_string.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_encode_ia5_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_encode_ia5_string.c
new file mode 100644
index 00000000000..82ed4666984
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_encode_ia5_string.c
@@ -0,0 +1,85 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_ia5_string.c
+ ASN.1 DER, encode a IA5 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Store an IA5 STRING
+ @param in The array of IA5 to store (one per char)
+ @param inlen The number of IA5 to store
+ @param out [out] The destination for the DER encoded IA5 STRING
+ @param outlen [in/out] The max size and resulting size of the DER IA5 STRING
+ @return CRYPT_OK if successful
+*/
+int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get the size */
+ if ((err = der_length_ia5_string(in, inlen, &len)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* too big? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* encode the header+len */
+ x = 0;
+ out[x++] = 0x16;
+ if (inlen < 128) {
+ out[x++] = (unsigned char)inlen;
+ } else if (inlen < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)inlen;
+ } else if (inlen < 65536UL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((inlen>>8)&255);
+ out[x++] = (unsigned char)(inlen&255);
+ } else if (inlen < 16777216UL) {
+ out[x++] = 0x83;
+ out[x++] = (unsigned char)((inlen>>16)&255);
+ out[x++] = (unsigned char)((inlen>>8)&255);
+ out[x++] = (unsigned char)(inlen&255);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* store octets */
+ for (y = 0; y < inlen; y++) {
+ out[x++] = der_ia5_char_encode(in[y]);
+ }
+
+ /* retun length */
+ *outlen = x;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/ia5/der_encode_ia5_string.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_length_ia5_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_length_ia5_string.c
new file mode 100644
index 00000000000..4d60f8ead7b
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/ia5/der_length_ia5_string.c
@@ -0,0 +1,194 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_ia5_string.c
+ ASN.1 DER, get length of IA5 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+ int code, value;
+} ia5_table[] = {
+{ '\0', 0 },
+{ '\a', 7 },
+{ '\b', 8 },
+{ '\t', 9 },
+{ '\n', 10 },
+{ '\f', 12 },
+{ '\r', 13 },
+{ ' ', 32 },
+{ '!', 33 },
+{ '"', 34 },
+{ '#', 35 },
+{ '$', 36 },
+{ '%', 37 },
+{ '&', 38 },
+{ '\'', 39 },
+{ '(', 40 },
+{ ')', 41 },
+{ '*', 42 },
+{ '+', 43 },
+{ ',', 44 },
+{ '-', 45 },
+{ '.', 46 },
+{ '/', 47 },
+{ '0', 48 },
+{ '1', 49 },
+{ '2', 50 },
+{ '3', 51 },
+{ '4', 52 },
+{ '5', 53 },
+{ '6', 54 },
+{ '7', 55 },
+{ '8', 56 },
+{ '9', 57 },
+{ ':', 58 },
+{ ';', 59 },
+{ '<', 60 },
+{ '=', 61 },
+{ '>', 62 },
+{ '?', 63 },
+{ '@', 64 },
+{ 'A', 65 },
+{ 'B', 66 },
+{ 'C', 67 },
+{ 'D', 68 },
+{ 'E', 69 },
+{ 'F', 70 },
+{ 'G', 71 },
+{ 'H', 72 },
+{ 'I', 73 },
+{ 'J', 74 },
+{ 'K', 75 },
+{ 'L', 76 },
+{ 'M', 77 },
+{ 'N', 78 },
+{ 'O', 79 },
+{ 'P', 80 },
+{ 'Q', 81 },
+{ 'R', 82 },
+{ 'S', 83 },
+{ 'T', 84 },
+{ 'U', 85 },
+{ 'V', 86 },
+{ 'W', 87 },
+{ 'X', 88 },
+{ 'Y', 89 },
+{ 'Z', 90 },
+{ '[', 91 },
+{ '\\', 92 },
+{ ']', 93 },
+{ '^', 94 },
+{ '_', 95 },
+{ '`', 96 },
+{ 'a', 97 },
+{ 'b', 98 },
+{ 'c', 99 },
+{ 'd', 100 },
+{ 'e', 101 },
+{ 'f', 102 },
+{ 'g', 103 },
+{ 'h', 104 },
+{ 'i', 105 },
+{ 'j', 106 },
+{ 'k', 107 },
+{ 'l', 108 },
+{ 'm', 109 },
+{ 'n', 110 },
+{ 'o', 111 },
+{ 'p', 112 },
+{ 'q', 113 },
+{ 'r', 114 },
+{ 's', 115 },
+{ 't', 116 },
+{ 'u', 117 },
+{ 'v', 118 },
+{ 'w', 119 },
+{ 'x', 120 },
+{ 'y', 121 },
+{ 'z', 122 },
+{ '{', 123 },
+{ '|', 124 },
+{ '}', 125 },
+{ '~', 126 }
+};
+
+int der_ia5_char_encode(int c)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
+ if (ia5_table[x].code == c) {
+ return ia5_table[x].value;
+ }
+ }
+ return -1;
+}
+
+int der_ia5_value_decode(int v)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
+ if (ia5_table[x].value == v) {
+ return ia5_table[x].code;
+ }
+ }
+ return -1;
+}
+
+/**
+ Gets length of DER encoding of IA5 STRING
+ @param octets The values you want to encode
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+ unsigned long x;
+
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(octets != NULL);
+
+ /* scan string for validity */
+ for (x = 0; x < noctets; x++) {
+ if (der_ia5_char_encode(octets[x]) == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ if (noctets < 128) {
+ /* 16 LL DD DD DD ... */
+ *outlen = 2 + noctets;
+ } else if (noctets < 256) {
+ /* 16 81 LL DD DD DD ... */
+ *outlen = 3 + noctets;
+ } else if (noctets < 65536UL) {
+ /* 16 82 LL LL DD DD DD ... */
+ *outlen = 4 + noctets;
+ } else if (noctets < 16777216UL) {
+ /* 16 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + noctets;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/ia5/der_length_ia5_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_decode_integer.c b/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_decode_integer.c
new file mode 100644
index 00000000000..d7b13cfa7c8
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_decode_integer.c
@@ -0,0 +1,110 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_integer.c
+ ASN.1 DER, decode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Read a mp_int integer
+ @param in The DER encoded data
+ @param inlen Size of DER encoded data
+ @param num The first mp_int to decode
+ @return CRYPT_OK if successful
+*/
+int der_decode_integer(const unsigned char *in, unsigned long inlen, mp_int_t num)
+{
+ unsigned long x, y, z;
+ int err;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(in != NULL);
+
+ /* min DER INTEGER is 0x02 01 00 == 0 */
+ if (inlen < (1 + 1 + 1)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* ok expect 0x02 when we AND with 0001 1111 [1F] */
+ x = 0;
+ if ((in[x++] & 0x1F) != 0x02) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* now decode the len stuff */
+ z = in[x++];
+
+ if ((z & 0x80) == 0x00) {
+ /* short form */
+
+ /* will it overflow? */
+ if (x + z > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* no so read it */
+ if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, z)) != CRYPT_OK) {
+ return err;
+ }
+ } else {
+ /* long form */
+ z &= 0x7F;
+
+ /* will number of length bytes overflow? (or > 4) */
+ if (((x + z) > inlen) || (z > 4) || (z == 0)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* now read it in */
+ y = 0;
+ while (z--) {
+ y = ((unsigned long)(in[x++])) | (y << 8);
+ }
+
+ /* now will reading y bytes overrun? */
+ if ((x + y) > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* no so read it */
+ if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* see if it's negative */
+ if (in[x] & 0x80) {
+ mp_int tmp;
+ if (mp_init(&tmp) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ if (mp_2expt(&tmp, mp_count_bits(num)) != CRYPT_OK || mp_sub(num, &tmp, num) != CRYPT_OK) {
+ mp_clear(&tmp);
+ return CRYPT_MEM;
+ }
+ mp_clear(&tmp);
+ }
+
+ return CRYPT_OK;
+
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/integer/der_decode_integer.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_encode_integer.c b/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_encode_integer.c
new file mode 100644
index 00000000000..830446a26cc
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_encode_integer.c
@@ -0,0 +1,130 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_integer.c
+ ASN.1 DER, encode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/* Exports a positive bignum as DER format (upto 2^32 bytes in size) */
+/**
+ Store a mp_int integer
+ @param num The first mp_int to encode
+ @param out [out] The destination for the DER encoded integers
+ @param outlen [in/out] The max size and resulting size of the DER encoded integers
+ @return CRYPT_OK if successful
+*/
+int der_encode_integer(mp_int_t num, unsigned char *out, unsigned long *outlen)
+{
+ unsigned long tmplen, y;
+ int err, leading_zero;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* find out how big this will be */
+ if ((err = der_length_integer(num, &tmplen)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (*outlen < tmplen) {
+ *outlen = tmplen;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (mp_cmp_d(num, 0) != LTC_MP_LT) {
+ /* we only need a leading zero if the msb of the first byte is one */
+ if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
+ leading_zero = 1;
+ } else {
+ leading_zero = 0;
+ }
+
+ /* get length of num in bytes (plus 1 since we force the msbyte to zero) */
+ y = mp_unsigned_bin_size(num) + leading_zero;
+ } else {
+ leading_zero = 0;
+ y = mp_count_bits(num);
+ y = y + (8 - (y & 7));
+ y = y >> 3;
+ if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --y;
+ }
+
+ /* now store initial data */
+ *out++ = 0x02;
+ if (y < 128) {
+ /* short form */
+ *out++ = (unsigned char)y;
+ } else if (y < 256) {
+ *out++ = 0x81;
+ *out++ = (unsigned char)y;
+ } else if (y < 65536UL) {
+ *out++ = 0x82;
+ *out++ = (unsigned char)((y>>8)&255);
+ *out++ = (unsigned char)y;
+ } else if (y < 16777216UL) {
+ *out++ = 0x83;
+ *out++ = (unsigned char)((y>>16)&255);
+ *out++ = (unsigned char)((y>>8)&255);
+ *out++ = (unsigned char)y;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* now store msbyte of zero if num is non-zero */
+ if (leading_zero) {
+ *out++ = 0x00;
+ }
+
+ /* if it's not zero store it as big endian */
+ if (mp_cmp_d(num, 0) == LTC_MP_GT) {
+ /* now store the mpint */
+ if ((err = mp_to_unsigned_bin(num, out)) != CRYPT_OK) {
+ return err;
+ }
+ } else if (mp_iszero(num) != LTC_MP_YES) {
+ mp_int tmp;
+
+ /* negative */
+ if (mp_init(&tmp) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ /* 2^roundup and subtract */
+ y = mp_count_bits(num);
+ y = y + (8 - (y & 7));
+ if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) y -= 8;
+ if (mp_2expt(&tmp, y) != CRYPT_OK || mp_add(&tmp, num, &tmp) != CRYPT_OK) {
+ mp_clear(&tmp);
+ return CRYPT_MEM;
+ }
+ if ((err = mp_to_unsigned_bin(&tmp, out)) != CRYPT_OK) {
+ mp_clear(&tmp);
+ return err;
+ }
+ mp_clear(&tmp);
+ }
+
+ /* we good */
+ *outlen = tmplen;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/integer/der_encode_integer.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_length_integer.c b/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_length_integer.c
new file mode 100644
index 00000000000..40addd5842b
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/integer/der_length_integer.c
@@ -0,0 +1,82 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_integer.c
+ ASN.1 DER, get length of encoding, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of num
+ @param num The int to get the size of
+ @param outlen [out] The length of the DER encoding for the given integer
+ @return CRYPT_OK if successful
+*/
+int der_length_integer(mp_int_t num, unsigned long *outlen)
+{
+ unsigned long z, len;
+ int leading_zero;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if (mp_cmp_d(num, 0) != LTC_MP_LT) {
+ /* positive */
+
+ /* we only need a leading zero if the msb of the first byte is one */
+ if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
+ leading_zero = 1;
+ } else {
+ leading_zero = 0;
+ }
+
+ /* size for bignum */
+ z = len = leading_zero + mp_unsigned_bin_size(num);
+ } else {
+ /* it's negative */
+ /* find power of 2 that is a multiple of eight and greater than count bits */
+ leading_zero = 0;
+ z = mp_count_bits(num);
+ z = z + (8 - (z & 7));
+ if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --z;
+ len = z = z >> 3;
+ }
+
+ /* now we need a length */
+ if (z < 128) {
+ /* short form */
+ ++len;
+ } else {
+ /* long form (relies on z != 0), assumes length bytes < 128 */
+ ++len;
+
+ while (z) {
+ ++len;
+ z >>= 8;
+ }
+ }
+
+ /* we need a 0x02 to indicate it's INTEGER */
+ ++len;
+
+ /* return length */
+ *outlen = len;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/integer/der_length_integer.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_decode_object_identifier.c b/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_decode_object_identifier.c
new file mode 100644
index 00000000000..cdd296d27b2
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_decode_object_identifier.c
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_object_identifier.c
+ ASN.1 DER, Decode Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Decode OID data and store the array of integers in words
+ @param in The OID DER encoded data
+ @param inlen The length of the OID data
+ @param words [out] The destination of the OID words
+ @param outlen [in/out] The number of OID words
+ @return CRYPT_OK if successful
+*/
+int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
+ unsigned long *words, unsigned long *outlen)
+{
+ unsigned long x, y, t, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(words != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* header is at least 3 bytes */
+ if (inlen < 3) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* must be room for at least two words */
+ if (*outlen < 2) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* decode the packet header */
+ x = 0;
+ if ((in[x++] & 0x1F) != 0x06) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* get the length */
+ if (in[x] < 128) {
+ len = in[x++];
+ } else {
+ if (in[x] < 0x81 || in[x] > 0x82) {
+ return CRYPT_INVALID_PACKET;
+ }
+ y = in[x++] & 0x7F;
+ len = 0;
+ while (y--) {
+ len = (len << 8) | (unsigned long)in[x++];
+ }
+ }
+
+ if (len < 1 || (len + x) > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* decode words */
+ y = 0;
+ t = 0;
+ while (len--) {
+ t = (t << 7) | (in[x] & 0x7F);
+ if (!(in[x++] & 0x80)) {
+ /* store t */
+ if (y >= *outlen) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ if (y == 0) {
+ words[0] = t / 40;
+ words[1] = t % 40;
+ y = 2;
+ } else {
+ words[y++] = t;
+ }
+ t = 0;
+ }
+ }
+
+ *outlen = y;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_encode_object_identifier.c b/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_encode_object_identifier.c
new file mode 100644
index 00000000000..b26ebdf5170
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_encode_object_identifier.c
@@ -0,0 +1,111 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_object_identifier.c
+ ASN.1 DER, Encode Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Encode an OID
+ @param words The words to encode (upto 32-bits each)
+ @param nwords The number of words in the OID
+ @param out [out] Destination of OID data
+ @param outlen [in/out] The max and resulting size of the OID
+ @return CRYPT_OK if successful
+*/
+int der_encode_object_identifier(unsigned long *words, unsigned long nwords,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long i, x, y, z, t, mask, wordbuf;
+ int err;
+
+ LTC_ARGCHK(words != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* check length */
+ if ((err = der_length_object_identifier(words, nwords, &x)) != CRYPT_OK) {
+ return err;
+ }
+ if (x > *outlen) {
+ *outlen = x;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* compute length to store OID data */
+ z = 0;
+ wordbuf = words[0] * 40 + words[1];
+ for (y = 1; y < nwords; y++) {
+ t = der_object_identifier_bits(wordbuf);
+ z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
+ if (y < nwords - 1) {
+ wordbuf = words[y + 1];
+ }
+ }
+
+ /* store header + length */
+ x = 0;
+ out[x++] = 0x06;
+ if (z < 128) {
+ out[x++] = (unsigned char)z;
+ } else if (z < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)z;
+ } else if (z < 65536UL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((z>>8)&255);
+ out[x++] = (unsigned char)(z&255);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* store first byte */
+ wordbuf = words[0] * 40 + words[1];
+ for (i = 1; i < nwords; i++) {
+ /* store 7 bit words in little endian */
+ t = wordbuf & 0xFFFFFFFF;
+ if (t) {
+ y = x;
+ mask = 0;
+ while (t) {
+ out[x++] = (unsigned char)((t & 0x7F) | mask);
+ t >>= 7;
+ mask |= 0x80; /* upper bit is set on all but the last byte */
+ }
+ /* now swap bytes y...x-1 */
+ z = x - 1;
+ while (y < z) {
+ t = out[y]; out[y] = out[z]; out[z] = (unsigned char)t;
+ ++y;
+ --z;
+ }
+ } else {
+ /* zero word */
+ out[x++] = 0x00;
+ }
+
+ if (i < nwords - 1) {
+ wordbuf = words[i + 1];
+ }
+ }
+
+ *outlen = x;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_length_object_identifier.c b/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_length_object_identifier.c
new file mode 100644
index 00000000000..ada54ab720d
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/object_identifier/der_length_object_identifier.c
@@ -0,0 +1,89 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_object_identifier.c
+ ASN.1 DER, get length of Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+unsigned long der_object_identifier_bits(unsigned long x)
+{
+ unsigned long c;
+ x &= 0xFFFFFFFF;
+ c = 0;
+ while (x) {
+ ++c;
+ x >>= 1;
+ }
+ return c;
+}
+
+
+/**
+ Gets length of DER encoding of Object Identifier
+ @param nwords The number of OID words
+ @param words The actual OID words to get the size of
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen)
+{
+ unsigned long y, z, t, wordbuf;
+
+ LTC_ARGCHK(words != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+
+ /* must be >= 2 words */
+ if (nwords < 2) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* word1 = 0,1,2,3 and word2 0..39 */
+ if (words[0] > 3 || (words[0] < 2 && words[1] > 39)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* leading word is the first two */
+ z = 0;
+ wordbuf = words[0] * 40 + words[1];
+ for (y = 1; y < nwords; y++) {
+ t = der_object_identifier_bits(wordbuf);
+ z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
+ if (y < nwords - 1) {
+ /* grab next word */
+ wordbuf = words[y+1];
+ }
+ }
+
+ /* now depending on the length our length encoding changes */
+ if (z < 128) {
+ z += 2;
+ } else if (z < 256) {
+ z += 3;
+ } else if (z < 65536UL) {
+ z += 4;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *outlen = z;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/object_identifier/der_length_object_identifier.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_decode_octet_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_decode_octet_string.c
new file mode 100644
index 00000000000..ab5bc10e3bd
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_decode_octet_string.c
@@ -0,0 +1,91 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_octet_string.c
+ ASN.1 DER, encode a OCTET STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a OCTET STRING
+ @param in The DER encoded OCTET STRING
+ @param inlen The size of the DER OCTET STRING
+ @param out [out] The array of octets stored (one per char)
+ @param outlen [in/out] The number of octets stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x04 */
+ if ((in[0] & 0x1F) != 0x04) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ /* is it too long? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data */
+ for (y = 0; y < len; y++) {
+ out[y] = in[x++];
+ }
+
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/octet/der_decode_octet_string.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_encode_octet_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_encode_octet_string.c
new file mode 100644
index 00000000000..64a07709e03
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_encode_octet_string.c
@@ -0,0 +1,86 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_octet_string.c
+ ASN.1 DER, encode a OCTET STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store an OCTET STRING
+ @param in The array of OCTETS to store (one per char)
+ @param inlen The number of OCTETS to store
+ @param out [out] The destination for the DER encoded OCTET STRING
+ @param outlen [in/out] The max size and resulting size of the DER OCTET STRING
+ @return CRYPT_OK if successful
+*/
+int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get the size */
+ if ((err = der_length_octet_string(inlen, &len)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* too big? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* encode the header+len */
+ x = 0;
+ out[x++] = 0x04;
+ if (inlen < 128) {
+ out[x++] = (unsigned char)inlen;
+ } else if (inlen < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)inlen;
+ } else if (inlen < 65536UL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((inlen>>8)&255);
+ out[x++] = (unsigned char)(inlen&255);
+ } else if (inlen < 16777216UL) {
+ out[x++] = 0x83;
+ out[x++] = (unsigned char)((inlen>>16)&255);
+ out[x++] = (unsigned char)((inlen>>8)&255);
+ out[x++] = (unsigned char)(inlen&255);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* store octets */
+ for (y = 0; y < inlen; y++) {
+ out[x++] = in[y];
+ }
+
+ /* retun length */
+ *outlen = x;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/octet/der_encode_octet_string.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_length_octet_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_length_octet_string.c
new file mode 100644
index 00000000000..c49415951b2
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/octet/der_length_octet_string.c
@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_octet_string.c
+ ASN.1 DER, get length of OCTET STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of OCTET STRING
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+
+ if (noctets < 128) {
+ /* 04 LL DD DD DD ... */
+ *outlen = 2 + noctets;
+ } else if (noctets < 256) {
+ /* 04 81 LL DD DD DD ... */
+ *outlen = 3 + noctets;
+ } else if (noctets < 65536UL) {
+ /* 04 82 LL LL DD DD DD ... */
+ *outlen = 4 + noctets;
+ } else if (noctets < 16777216UL) {
+ /* 04 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + noctets;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/octet/der_length_octet_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_decode_printable_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_decode_printable_string.c
new file mode 100644
index 00000000000..8504f7719dd
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_decode_printable_string.c
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_printable_string.c
+ ASN.1 DER, encode a printable STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a printable STRING
+ @param in The DER encoded printable STRING
+ @param inlen The size of the DER printable STRING
+ @param out [out] The array of octets stored (one per char)
+ @param outlen [in/out] The number of octets stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int t;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x13 */
+ if ((in[0] & 0x1F) != 0x13) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ /* is it too long? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the data */
+ for (y = 0; y < len; y++) {
+ t = der_printable_value_decode(in[x++]);
+ if (t == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ out[y] = t;
+ }
+
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/printable_string/der_decode_printable_string.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_encode_printable_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_encode_printable_string.c
new file mode 100644
index 00000000000..deccdee88aa
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_encode_printable_string.c
@@ -0,0 +1,85 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_printable_string.c
+ ASN.1 DER, encode a printable STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Store an printable STRING
+ @param in The array of printable to store (one per char)
+ @param inlen The number of printable to store
+ @param out [out] The destination for the DER encoded printable STRING
+ @param outlen [in/out] The max size and resulting size of the DER printable STRING
+ @return CRYPT_OK if successful
+*/
+int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get the size */
+ if ((err = der_length_printable_string(in, inlen, &len)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* too big? */
+ if (len > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* encode the header+len */
+ x = 0;
+ out[x++] = 0x13;
+ if (inlen < 128) {
+ out[x++] = (unsigned char)inlen;
+ } else if (inlen < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)inlen;
+ } else if (inlen < 65536UL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((inlen>>8)&255);
+ out[x++] = (unsigned char)(inlen&255);
+ } else if (inlen < 16777216UL) {
+ out[x++] = 0x83;
+ out[x++] = (unsigned char)((inlen>>16)&255);
+ out[x++] = (unsigned char)((inlen>>8)&255);
+ out[x++] = (unsigned char)(inlen&255);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* store octets */
+ for (y = 0; y < inlen; y++) {
+ out[x++] = der_printable_char_encode(in[y]);
+ }
+
+ /* retun length */
+ *outlen = x;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/printable_string/der_encode_printable_string.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_length_printable_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_length_printable_string.c
new file mode 100644
index 00000000000..997d3b5f9e9
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/printable_string/der_length_printable_string.c
@@ -0,0 +1,166 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_printable_string.c
+ ASN.1 DER, get length of Printable STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+ int code, value;
+} printable_table[] = {
+{ ' ', 32 },
+{ '\'', 39 },
+{ '(', 40 },
+{ ')', 41 },
+{ '+', 43 },
+{ ',', 44 },
+{ '-', 45 },
+{ '.', 46 },
+{ '/', 47 },
+{ '0', 48 },
+{ '1', 49 },
+{ '2', 50 },
+{ '3', 51 },
+{ '4', 52 },
+{ '5', 53 },
+{ '6', 54 },
+{ '7', 55 },
+{ '8', 56 },
+{ '9', 57 },
+{ ':', 58 },
+{ '=', 61 },
+{ '?', 63 },
+{ 'A', 65 },
+{ 'B', 66 },
+{ 'C', 67 },
+{ 'D', 68 },
+{ 'E', 69 },
+{ 'F', 70 },
+{ 'G', 71 },
+{ 'H', 72 },
+{ 'I', 73 },
+{ 'J', 74 },
+{ 'K', 75 },
+{ 'L', 76 },
+{ 'M', 77 },
+{ 'N', 78 },
+{ 'O', 79 },
+{ 'P', 80 },
+{ 'Q', 81 },
+{ 'R', 82 },
+{ 'S', 83 },
+{ 'T', 84 },
+{ 'U', 85 },
+{ 'V', 86 },
+{ 'W', 87 },
+{ 'X', 88 },
+{ 'Y', 89 },
+{ 'Z', 90 },
+{ 'a', 97 },
+{ 'b', 98 },
+{ 'c', 99 },
+{ 'd', 100 },
+{ 'e', 101 },
+{ 'f', 102 },
+{ 'g', 103 },
+{ 'h', 104 },
+{ 'i', 105 },
+{ 'j', 106 },
+{ 'k', 107 },
+{ 'l', 108 },
+{ 'm', 109 },
+{ 'n', 110 },
+{ 'o', 111 },
+{ 'p', 112 },
+{ 'q', 113 },
+{ 'r', 114 },
+{ 's', 115 },
+{ 't', 116 },
+{ 'u', 117 },
+{ 'v', 118 },
+{ 'w', 119 },
+{ 'x', 120 },
+{ 'y', 121 },
+{ 'z', 122 },
+};
+
+int der_printable_char_encode(int c)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
+ if (printable_table[x].code == c) {
+ return printable_table[x].value;
+ }
+ }
+ return -1;
+}
+
+int der_printable_value_decode(int v)
+{
+ int x;
+ for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
+ if (printable_table[x].value == v) {
+ return printable_table[x].code;
+ }
+ }
+ return -1;
+}
+
+/**
+ Gets length of DER encoding of Printable STRING
+ @param octets The values you want to encode
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+ unsigned long x;
+
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(octets != NULL);
+
+ /* scan string for validity */
+ for (x = 0; x < noctets; x++) {
+ if (der_printable_char_encode(octets[x]) == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ if (noctets < 128) {
+ /* 16 LL DD DD DD ... */
+ *outlen = 2 + noctets;
+ } else if (noctets < 256) {
+ /* 16 81 LL DD DD DD ... */
+ *outlen = 3 + noctets;
+ } else if (noctets < 65536UL) {
+ /* 16 82 LL LL DD DD DD ... */
+ *outlen = 4 + noctets;
+ } else if (noctets < 16777216UL) {
+ /* 16 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + noctets;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/printable_string/der_length_printable_string.c,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_ex.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_ex.c
new file mode 100644
index 00000000000..20674370be5
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_ex.c
@@ -0,0 +1,287 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+
+/**
+ @file der_decode_sequence_ex.c
+ ASN.1 DER, decode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a SEQUENCE
+ @param in The DER encoded input
+ @param inlen The size of the input
+ @param list The list of items to decode
+ @param outlen The number of items in the list
+ @param ordered Search an unordeded or ordered list
+ @return CRYPT_OK on success
+*/
+int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *list, unsigned long outlen, int ordered)
+{
+ int err, type;
+ unsigned long size, x, y, z, i, blksize;
+ void *data;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(list != NULL);
+
+ /* get blk size */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
+ x = 0;
+ if (in[x] != 0x30 && in[x] != 0x31) {
+ return CRYPT_INVALID_PACKET;
+ }
+ ++x;
+
+ if (in[x] < 128) {
+ blksize = in[x++];
+ } else if (in[x] & 0x80) {
+ if (in[x] < 0x81 || in[x] > 0x83) {
+ return CRYPT_INVALID_PACKET;
+ }
+ y = in[x++] & 0x7F;
+
+ /* would reading the len bytes overrun? */
+ if (x + y > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read len */
+ blksize = 0;
+ while (y--) {
+ blksize = (blksize << 8) | (unsigned long)in[x++];
+ }
+ }
+
+ /* would this blksize overflow? */
+ if (x + blksize > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* mark all as unused */
+ for (i = 0; i < outlen; i++) {
+ list[i].used = 0;
+ }
+
+ /* ok read data */
+ inlen = blksize;
+ for (i = 0; i < outlen; i++) {
+ z = 0;
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+ if (!ordered && list[i].used == 1) { continue; }
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ z = inlen;
+ if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = der_length_boolean(&z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_INTEGER:
+ z = inlen;
+ if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ z = inlen;
+ if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ z = inlen;
+ if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ z = inlen;
+ if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_NULL:
+ if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
+ if (!ordered) { continue; }
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ z = 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ z = inlen;
+ if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ z = inlen;
+ if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ z = inlen;
+ if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ z = inlen;
+ if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = inlen;
+ if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SET:
+ z = inlen;
+ if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ /* detect if we have the right type */
+ if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ z = inlen;
+ if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+
+ case LTC_ASN1_CHOICE:
+ z = inlen;
+ if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
+ if (!ordered) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ default:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ x += z;
+ inlen -= z;
+ list[i].used = 1;
+ if (!ordered) {
+ /* restart the decoder */
+ i = -1;
+ }
+ }
+
+ for (i = 0; i < outlen; i++) {
+ if (list[i].used == 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ }
+ err = CRYPT_OK;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_ex.c,v $ */
+/* $Revision: 1.16 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_flexi.c
new file mode 100644
index 00000000000..e84f72e7cd9
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_flexi.c
@@ -0,0 +1,394 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file der_decode_sequence_flexi.c
+ ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static unsigned long fetch_length(const unsigned char *in, unsigned long inlen)
+{
+ unsigned long x, y, z;
+
+ y = 0;
+
+ /* skip type and read len */
+ if (inlen < 2) {
+ return 0xFFFFFFFF;
+ }
+ ++in; ++y;
+
+ /* read len */
+ x = *in++; ++y;
+
+ /* <128 means literal */
+ if (x < 128) {
+ return x+y;
+ }
+ x &= 0x7F; /* the lower 7 bits are the length of the length */
+ inlen -= 2;
+
+ /* len means len of len! */
+ if (x == 0 || x > 4 || x > inlen) {
+ return 0xFFFFFFFF;
+ }
+
+ y += x;
+ z = 0;
+ while (x--) {
+ z = (z<<8) | ((unsigned long)*in);
+ ++in;
+ }
+ return z+y;
+}
+
+/**
+ ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
+ @param in The input buffer
+ @param inlen [in/out] The length of the input buffer and on output the amount of decoded data
+ @param out [out] A pointer to the linked list
+ @return CRYPT_OK on success.
+*/
+int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
+{
+ ltc_asn1_list *l;
+ unsigned long err, type, len, totlen, x, y;
+ void *realloc_tmp;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ l = NULL;
+ totlen = 0;
+
+ /* scan the input and and get lengths and what not */
+ while (*inlen) {
+ /* read the type byte */
+ type = *in;
+
+ /* fetch length */
+ len = fetch_length(in, *inlen);
+ if (len > *inlen) {
+ err = CRYPT_INVALID_PACKET;
+ goto error;
+ }
+
+ /* alloc new link */
+ if (l == NULL) {
+ l = XCALLOC(1, sizeof(*l));
+ if (l == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+ } else {
+ l->next = XCALLOC(1, sizeof(*l));
+ if (l->next == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+ l->next->prev = l;
+ l = l->next;
+ }
+
+ /* now switch on type */
+ switch (type) {
+ case 0x01: /* BOOLEAN */
+ l->type = LTC_ASN1_BOOLEAN;
+ l->size = 1;
+ l->data = XCALLOC(1, sizeof(int));
+
+ if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_boolean(&len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x02: /* INTEGER */
+ /* init field */
+ l->type = LTC_ASN1_INTEGER;
+ l->size = 1;
+
+ l->data = XMALLOC(sizeof(mp_int));
+ if (l->data == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = mp_init((mp_int_t)l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* decode field */
+ if ((err = der_decode_integer(in, *inlen, (mp_int_t)l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* calc length of object */
+ if ((err = der_length_integer((mp_int_t)l->data, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x03: /* BIT */
+ /* init field */
+ l->type = LTC_ASN1_BIT_STRING;
+ l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char. */
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x04: /* OCTET */
+
+ /* init field */
+ l->type = LTC_ASN1_OCTET_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x05: /* NULL */
+
+ /* valid NULL is 0x05 0x00 */
+ if (in[0] != 0x05 || in[1] != 0x00) {
+ err = CRYPT_INVALID_PACKET;
+ goto error;
+ }
+
+ /* simple to store ;-) */
+ l->type = LTC_ASN1_NULL;
+ l->data = NULL;
+ l->size = 0;
+ len = 2;
+
+ break;
+
+ case 0x06: /* OID */
+
+ /* init field */
+ l->type = LTC_ASN1_OBJECT_IDENTIFIER;
+ l->size = len;
+
+ if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* resize it to save a bunch of mem */
+ if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
+ /* out of heap but this is not an error */
+ break;
+ }
+ l->data = realloc_tmp;
+ break;
+
+ case 0x0C: /* UTF8 */
+
+ /* init field */
+ l->type = LTC_ASN1_UTF8_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x13: /* PRINTABLE */
+
+ /* init field */
+ l->type = LTC_ASN1_PRINTABLE_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x16: /* IA5 */
+
+ /* init field */
+ l->type = LTC_ASN1_IA5_STRING;
+ l->size = len;
+
+ if ((l->data = XCALLOC(1, l->size)) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x17: /* UTC TIME */
+
+ /* init field */
+ l->type = LTC_ASN1_UTCTIME;
+ l->size = 1;
+
+ if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
+ err = CRYPT_MEM;
+ goto error;
+ }
+
+ len = *inlen;
+ if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
+ goto error;
+ }
+
+ if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
+ goto error;
+ }
+ break;
+
+ case 0x30: /* SEQUENCE */
+ case 0x31: /* SET */
+
+ /* init field */
+ l->type = (type == 0x30) ? LTC_ASN1_SEQUENCE : LTC_ASN1_SET;
+
+ /* we have to decode the SEQUENCE header and get it's length */
+
+ /* move past type */
+ ++in; --(*inlen);
+
+ /* read length byte */
+ x = *in++; --(*inlen);
+
+ /* smallest SEQUENCE/SET header */
+ y = 2;
+
+ /* now if it's > 127 the next bytes are the length of the length */
+ if (x > 128) {
+ x &= 0x7F;
+ in += x;
+ *inlen -= x;
+
+ /* update sequence header len */
+ y += x;
+ }
+
+ /* Sequence elements go as child */
+ len = len - y;
+ if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* len update */
+ totlen += y;
+
+ /* link them up y0 */
+ l->child->parent = l;
+
+ break;
+ default:
+ /* invalid byte ... this is a soft error */
+ /* remove link */
+ l = l->prev;
+ XFREE(l->next);
+ l->next = NULL;
+ goto outside;
+ }
+
+ /* advance pointers */
+ totlen += len;
+ in += len;
+ *inlen -= len;
+ }
+
+outside:
+
+ /* rewind l please */
+ while (l->prev != NULL || l->parent != NULL) {
+ if (l->parent != NULL) {
+ l = l->parent;
+ } else {
+ l = l->prev;
+ }
+ }
+
+ /* return */
+ *out = l;
+ *inlen = totlen;
+ return CRYPT_OK;
+
+error:
+ /* free list */
+ der_sequence_free(l);
+
+ return err;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c,v $ */
+/* $Revision: 1.26 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_multi.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_multi.c
new file mode 100644
index 00000000000..c064d9ee3ff
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_decode_sequence_multi.c
@@ -0,0 +1,140 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+
+
+/**
+ @file der_decode_sequence_multi.c
+ ASN.1 DER, decode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a SEQUENCE type using a VA list
+ @param in Input buffer
+ @param inlen Length of input in octets
+ @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
+{
+ int err, type;
+ unsigned long size, x;
+ void *data;
+ va_list args;
+ ltc_asn1_list *list;
+
+ LTC_ARGCHK(in != NULL);
+
+ /* get size of output that will be required */
+ va_start(args, inlen);
+ x = 0;
+ for (;;) {
+ type = va_arg(args, int);
+ size = va_arg(args, unsigned long);
+ data = va_arg(args, void*);
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER:
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_OCTET_STRING:
+ case LTC_ASN1_NULL:
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ case LTC_ASN1_IA5_STRING:
+ case LTC_ASN1_PRINTABLE_STRING:
+ case LTC_ASN1_UTF8_STRING:
+ case LTC_ASN1_UTCTIME:
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ case LTC_ASN1_CHOICE:
+ ++x;
+ break;
+
+ default:
+ va_end(args);
+ return CRYPT_INVALID_ARG;
+ }
+ }
+ va_end(args);
+
+ /* allocate structure for x elements */
+ if (x == 0) {
+ return CRYPT_NOP;
+ }
+
+ list = XCALLOC(sizeof(*list), x);
+ if (list == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* fill in the structure */
+ va_start(args, inlen);
+ x = 0;
+ for (;;) {
+ type = va_arg(args, int);
+ size = va_arg(args, unsigned long);
+ data = va_arg(args, void*);
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER:
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_OCTET_STRING:
+ case LTC_ASN1_NULL:
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ case LTC_ASN1_IA5_STRING:
+ case LTC_ASN1_PRINTABLE_STRING:
+ case LTC_ASN1_UTF8_STRING:
+ case LTC_ASN1_UTCTIME:
+ case LTC_ASN1_SEQUENCE:
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_CHOICE:
+ list[x].type = type;
+ list[x].size = size;
+ list[x++].data = data;
+ break;
+
+ default:
+ va_end(args);
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+ va_end(args);
+
+ err = der_decode_sequence(in, inlen, list, x);
+LBL_ERR:
+ XFREE(list);
+ return err;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_multi.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_ex.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_ex.c
new file mode 100644
index 00000000000..e92f7c310d6
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_ex.c
@@ -0,0 +1,335 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+
+/**
+ @file der_encode_sequence_ex.c
+ ASN.1 DER, encode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Encode a SEQUENCE
+ @param list The list of items to encode
+ @param inlen The number of items in the list
+ @param out [out] The destination
+ @param outlen [in/out] The size of the output
+ @param type_of LTC_ASN1_SEQUENCE or LTC_ASN1_SET/LTC_ASN1_SETOF
+ @return CRYPT_OK on success
+*/
+int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int type_of)
+{
+ int err, type;
+ unsigned long size, x, y, z, i;
+ void *data;
+
+ LTC_ARGCHK(list != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get size of output that will be required */
+ y = 0;
+ for (i = 0; i < inlen; i++) {
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ if ((err = der_length_boolean(&x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_INTEGER:
+ if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ if ((err = der_length_short_integer(*((unsigned long*)data), &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_NULL:
+ y += 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ default:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+
+ /* calc header size */
+ z = y;
+ if (y < 128) {
+ y += 2;
+ } else if (y < 256) {
+ /* 0x30 0x81 LL */
+ y += 3;
+ } else if (y < 65536UL) {
+ /* 0x30 0x82 LL LL */
+ y += 4;
+ } else if (y < 16777216UL) {
+ /* 0x30 0x83 LL LL LL */
+ y += 5;
+ } else {
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+
+ /* too big ? */
+ if (*outlen < y) {
+ *outlen = y;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ /* store header */
+ x = 0;
+ out[x++] = (type_of == LTC_ASN1_SEQUENCE) ? 0x30 : 0x31;
+
+ if (z < 128) {
+ out[x++] = (unsigned char)z;
+ } else if (z < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)z;
+ } else if (z < 65536UL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((z>>8UL)&255);
+ out[x++] = (unsigned char)(z&255);
+ } else if (z < 16777216UL) {
+ out[x++] = 0x83;
+ out[x++] = (unsigned char)((z>>16UL)&255);
+ out[x++] = (unsigned char)((z>>8UL)&255);
+ out[x++] = (unsigned char)(z&255);
+ }
+
+ /* store data */
+ *outlen -= x;
+ for (i = 0; i < inlen; i++) {
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ z = *outlen;
+ if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_INTEGER:
+ z = *outlen;
+ if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ z = *outlen;
+ if ((err = der_encode_short_integer(*((unsigned long*)data), out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ z = *outlen;
+ if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ z = *outlen;
+ if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_NULL:
+ out[x++] = 0x05;
+ out[x++] = 0x00;
+ *outlen -= 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ z = *outlen;
+ if ((err = der_encode_object_identifier(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ z = *outlen;
+ if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ z = *outlen;
+ if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ z = *outlen;
+ if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = *outlen;
+ if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_SET:
+ z = *outlen;
+ if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_SETOF:
+ z = *outlen;
+ if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ case LTC_ASN1_SEQUENCE:
+ z = *outlen;
+ if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += z;
+ *outlen -= z;
+ break;
+
+ default:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+ *outlen = x;
+ err = CRYPT_OK;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_multi.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_multi.c
new file mode 100644
index 00000000000..8d53c623965
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_encode_sequence_multi.c
@@ -0,0 +1,139 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+
+
+/**
+ @file der_encode_sequence_multi.c
+ ASN.1 DER, encode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Encode a SEQUENCE type using a VA list
+ @param out [out] Destination for data
+ @param outlen [in/out] Length of buffer and resulting length of output
+ @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
+{
+ int err, type;
+ unsigned long size, x;
+ void *data;
+ va_list args;
+ ltc_asn1_list *list;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get size of output that will be required */
+ va_start(args, outlen);
+ x = 0;
+ for (;;) {
+ type = va_arg(args, int);
+ size = va_arg(args, unsigned long);
+ data = va_arg(args, void*);
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER:
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_OCTET_STRING:
+ case LTC_ASN1_NULL:
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ case LTC_ASN1_IA5_STRING:
+ case LTC_ASN1_PRINTABLE_STRING:
+ case LTC_ASN1_UTF8_STRING:
+ case LTC_ASN1_UTCTIME:
+ case LTC_ASN1_SEQUENCE:
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ ++x;
+ break;
+
+ default:
+ va_end(args);
+ return CRYPT_INVALID_ARG;
+ }
+ }
+ va_end(args);
+
+ /* allocate structure for x elements */
+ if (x == 0) {
+ return CRYPT_NOP;
+ }
+
+ list = XCALLOC(sizeof(*list), x);
+ if (list == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* fill in the structure */
+ va_start(args, outlen);
+ x = 0;
+ for (;;) {
+ type = va_arg(args, int);
+ size = va_arg(args, unsigned long);
+ data = va_arg(args, void*);
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER:
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_OCTET_STRING:
+ case LTC_ASN1_NULL:
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ case LTC_ASN1_IA5_STRING:
+ case LTC_ASN1_PRINTABLE_STRING:
+ case LTC_ASN1_UTF8_STRING:
+ case LTC_ASN1_UTCTIME:
+ case LTC_ASN1_SEQUENCE:
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ list[x].type = type;
+ list[x].size = size;
+ list[x++].data = data;
+ break;
+
+ default:
+ va_end(args);
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+ va_end(args);
+
+ err = der_encode_sequence(list, x, out, outlen);
+LBL_ERR:
+ XFREE(list);
+ return err;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_multi.c,v $ */
+/* $Revision: 1.12 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_length_sequence.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_length_sequence.c
new file mode 100644
index 00000000000..d2e9803d75e
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_length_sequence.c
@@ -0,0 +1,169 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_sequence.c
+ ASN.1 DER, length a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Get the length of a DER sequence
+ @param list The sequences of items in the SEQUENCE
+ @param inlen The number of items
+ @param outlen [out] The length required in octets to store it
+ @return CRYPT_OK on success
+*/
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+ unsigned long *outlen)
+{
+ int err, type;
+ unsigned long size, x, y, z, i;
+ void *data;
+
+ LTC_ARGCHK(list != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get size of output that will be required */
+ y = 0;
+ for (i = 0; i < inlen; i++) {
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ if ((err = der_length_boolean(&x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_INTEGER:
+ if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ if ((err = der_length_short_integer(*((unsigned long *)data), &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_NULL:
+ y += 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+
+ default:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+
+ /* calc header size */
+ z = y;
+ if (y < 128) {
+ y += 2;
+ } else if (y < 256) {
+ /* 0x30 0x81 LL */
+ y += 3;
+ } else if (y < 65536UL) {
+ /* 0x30 0x82 LL LL */
+ y += 4;
+ } else if (y < 16777216UL) {
+ /* 0x30 0x83 LL LL LL */
+ y += 5;
+ } else {
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+
+ /* store size */
+ *outlen = y;
+ err = CRYPT_OK;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_length_sequence.c,v $ */
+/* $Revision: 1.14 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_sequence_free.c b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_sequence_free.c
new file mode 100644
index 00000000000..90a1297347d
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/sequence/der_sequence_free.c
@@ -0,0 +1,66 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file der_sequence_free.c
+ ASN.1 DER, free's a structure allocated by der_decode_sequence_flexi(), Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Free memory allocated by der_decode_sequence_flexi()
+ @param in The list to free
+*/
+void der_sequence_free(ltc_asn1_list *in)
+{
+ ltc_asn1_list *l;
+
+ /* walk to the start of the chain */
+ while (in->prev != NULL || in->parent != NULL) {
+ if (in->parent != NULL) {
+ in = in->parent;
+ } else {
+ in = in->prev;
+ }
+ }
+
+ /* now walk the list and free stuff */
+ while (in != NULL) {
+ /* is there a child? */
+ if (in->child) {
+ /* disconnect */
+ in->child->parent = NULL;
+ der_sequence_free(in->child);
+ }
+
+ switch (in->type) {
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE: break;
+ case LTC_ASN1_INTEGER : if (in->data != NULL) { mp_clear(in->data); XFREE(in->data); } break;
+ default : if (in->data != NULL) { XFREE(in->data); }
+ }
+
+ /* move to next and free current */
+ l = in->next;
+ XFREE(in);
+ in = l;
+ }
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_sequence_free.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_set.c b/crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_set.c
new file mode 100644
index 00000000000..8a13479a180
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_set.c
@@ -0,0 +1,104 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file der_encode_set.c
+ ASN.1 DER, Encode a SET, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/* LTC define to ASN.1 TAG */
+static int ltc_to_asn1(int v)
+{
+ switch (v) {
+ case LTC_ASN1_BOOLEAN: return 0x01;
+ case LTC_ASN1_INTEGER:
+ case LTC_ASN1_SHORT_INTEGER: return 0x02;
+ case LTC_ASN1_BIT_STRING: return 0x03;
+ case LTC_ASN1_OCTET_STRING: return 0x04;
+ case LTC_ASN1_NULL: return 0x05;
+ case LTC_ASN1_OBJECT_IDENTIFIER: return 0x06;
+ case LTC_ASN1_UTF8_STRING: return 0x0C;
+ case LTC_ASN1_PRINTABLE_STRING: return 0x13;
+ case LTC_ASN1_IA5_STRING: return 0x16;
+ case LTC_ASN1_UTCTIME: return 0x17;
+ case LTC_ASN1_SEQUENCE: return 0x30;
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF: return 0x31;
+ default: return -1;
+ }
+}
+
+
+static int qsort_helper(const void *a, const void *b)
+{
+ ltc_asn1_list *A = (ltc_asn1_list *)a, *B = (ltc_asn1_list *)b;
+ int r;
+
+ r = ltc_to_asn1(A->type) - ltc_to_asn1(B->type);
+
+ /* for QSORT the order is UNDEFINED if they are "equal" which means it is NOT DETERMINISTIC. So we force it to be :-) */
+ if (r == 0) {
+ /* their order in the original list now determines the position */
+ return A->used - B->used;
+ } else {
+ return r;
+ }
+}
+
+/*
+ Encode a SET type
+ @param list The list of items to encode
+ @param inlen The number of items in the list
+ @param out [out] The destination
+ @param outlen [in/out] The size of the output
+ @return CRYPT_OK on success
+*/
+int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ ltc_asn1_list *copy;
+ unsigned long x;
+ int err;
+
+ /* make copy of list */
+ copy = XCALLOC(inlen, sizeof(*copy));
+ if (copy == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* fill in used member with index so we can fully sort it */
+ for (x = 0; x < inlen; x++) {
+ copy[x] = list[x];
+ copy[x].used = x;
+ }
+
+ /* sort it by the "type" field */
+ XQSORT(copy, inlen, sizeof(*copy), &qsort_helper);
+
+ /* call der_encode_sequence_ex() */
+ err = der_encode_sequence_ex(copy, inlen, out, outlen, LTC_ASN1_SET);
+
+ /* free list */
+ XFREE(copy);
+
+ return err;
+}
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/set/der_encode_set.c,v $ */
+/* $Revision: 1.12 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_setof.c b/crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_setof.c
new file mode 100644
index 00000000000..aa1af729b6b
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/set/der_encode_setof.c
@@ -0,0 +1,163 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file der_encode_setof.c
+ ASN.1 DER, Encode SET OF, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+struct edge {
+ unsigned char *start;
+ unsigned long size;
+};
+
+static int qsort_helper(const void *a, const void *b)
+{
+ struct edge *A = (struct edge *)a, *B = (struct edge *)b;
+ int r;
+ unsigned long x;
+
+ /* compare min length */
+ r = XMEMCMP(A->start, B->start, MIN(A->size, B->size));
+
+ if (r == 0 && A->size != B->size) {
+ if (A->size > B->size) {
+ for (x = B->size; x < A->size; x++) {
+ if (A->start[x]) {
+ return 1;
+ }
+ }
+ } else {
+ for (x = A->size; x < B->size; x++) {
+ if (B->start[x]) {
+ return -1;
+ }
+ }
+ }
+ }
+
+ return r;
+}
+
+/**
+ Encode a SETOF stucture
+ @param list The list of items to encode
+ @param inlen The number of items in the list
+ @param out [out] The destination
+ @param outlen [in/out] The size of the output
+ @return CRYPT_OK on success
+*/
+int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, z, hdrlen;
+ int err;
+ struct edge *edges;
+ unsigned char *ptr, *buf;
+
+ /* check that they're all the same type */
+ for (x = 1; x < inlen; x++) {
+ if (list[x].type != list[x-1].type) {
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ /* alloc buffer to store copy of output */
+ buf = XCALLOC(1, *outlen);
+ if (buf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* encode list */
+ if ((err = der_encode_sequence_ex(list, inlen, buf, outlen, LTC_ASN1_SETOF)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+
+ /* allocate edges */
+ edges = XCALLOC(inlen, sizeof(*edges));
+ if (edges == NULL) {
+ XFREE(buf);
+ return CRYPT_MEM;
+ }
+
+ /* skip header */
+ ptr = buf + 1;
+
+ /* now skip length data */
+ x = *ptr++;
+ if (x >= 0x80) {
+ ptr += (x & 0x7F);
+ }
+
+ /* get the size of the static header */
+ hdrlen = ((unsigned long)ptr) - ((unsigned long)buf);
+
+
+ /* scan for edges */
+ x = 0;
+ while (ptr < (buf + *outlen)) {
+ /* store start */
+ edges[x].start = ptr;
+
+ /* skip type */
+ z = 1;
+
+ /* parse length */
+ y = ptr[z++];
+ if (y < 128) {
+ edges[x].size = y;
+ } else {
+ y &= 0x7F;
+ edges[x].size = 0;
+ while (y--) {
+ edges[x].size = (edges[x].size << 8) | ((unsigned long)ptr[z++]);
+ }
+ }
+
+ /* skip content */
+ edges[x].size += z;
+ ptr += edges[x].size;
+ ++x;
+ }
+
+ /* sort based on contents (using edges) */
+ XQSORT(edges, inlen, sizeof(*edges), &qsort_helper);
+
+ /* copy static header */
+ XMEMCPY(out, buf, hdrlen);
+
+ /* copy+sort using edges+indecies to output from buffer */
+ for (y = hdrlen, x = 0; x < inlen; x++) {
+ XMEMCPY(out+y, edges[x].start, edges[x].size);
+ y += edges[x].size;
+ }
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, *outlen);
+#endif
+
+ /* free buffers */
+ XFREE(edges);
+ XFREE(buf);
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/set/der_encode_setof.c,v $ */
+/* $Revision: 1.12 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_decode_short_integer.c b/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_decode_short_integer.c
new file mode 100644
index 00000000000..fbb89a4f850
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_decode_short_integer.c
@@ -0,0 +1,68 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_short_integer.c
+ ASN.1 DER, decode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Read a short integer
+ @param in The DER encoded data
+ @param inlen Size of data
+ @param num [out] The integer to decode
+ @return CRYPT_OK if successful
+*/
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num)
+{
+ unsigned long len, x, y;
+
+ LTC_ARGCHK(num != NULL);
+ LTC_ARGCHK(in != NULL);
+
+ /* check length */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check header */
+ x = 0;
+ if ((in[x++] & 0x1F) != 0x02) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* get the packet len */
+ len = in[x++];
+
+ if (x + len > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read number */
+ y = 0;
+ while (len--) {
+ y = (y<<8) | (unsigned long)in[x++];
+ }
+ *num = y;
+
+ return CRYPT_OK;
+
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/short_integer/der_decode_short_integer.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_encode_short_integer.c b/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_encode_short_integer.c
new file mode 100644
index 00000000000..cd9e6d1015e
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_encode_short_integer.c
@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_short_integer.c
+ ASN.1 DER, encode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a short integer in the range (0,2^32-1)
+ @param num The integer to encode
+ @param out [out] The destination for the DER encoded integers
+ @param outlen [in/out] The max size and resulting size of the DER encoded integers
+ @return CRYPT_OK if successful
+*/
+int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen)
+{
+ unsigned long len, x, y, z;
+ int err;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* force to 32 bits */
+ num &= 0xFFFFFFFFUL;
+
+ /* find out how big this will be */
+ if ((err = der_length_short_integer(num, &len)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (*outlen < len) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* get len of output */
+ z = 0;
+ y = num;
+ while (y) {
+ ++z;
+ y >>= 8;
+ }
+
+ /* handle zero */
+ if (z == 0) {
+ z = 1;
+ }
+
+ /* see if msb is set */
+ z += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
+
+ /* adjust the number so the msB is non-zero */
+ for (x = 0; (z <= 4) && (x < (4 - z)); x++) {
+ num <<= 8;
+ }
+
+ /* store header */
+ x = 0;
+ out[x++] = 0x02;
+ out[x++] = (unsigned char)z;
+
+ /* if 31st bit is set output a leading zero and decrement count */
+ if (z == 5) {
+ out[x++] = 0;
+ --z;
+ }
+
+ /* store values */
+ for (y = 0; y < z; y++) {
+ out[x++] = (unsigned char)((num >> 24) & 0xFF);
+ num <<= 8;
+ }
+
+ /* we good */
+ *outlen = x;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/short_integer/der_encode_short_integer.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_length_short_integer.c b/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_length_short_integer.c
new file mode 100644
index 00000000000..ec3f8f14f82
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/short_integer/der_length_short_integer.c
@@ -0,0 +1,70 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_short_integer.c
+ ASN.1 DER, get length of encoding, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+/**
+ Gets length of DER encoding of num
+ @param num The integer to get the size of
+ @param outlen [out] The length of the DER encoding for the given integer
+ @return CRYPT_OK if successful
+*/
+int der_length_short_integer(unsigned long num, unsigned long *outlen)
+{
+ unsigned long z, y, len;
+
+ LTC_ARGCHK(outlen != NULL);
+
+ /* force to 32 bits */
+ num &= 0xFFFFFFFFUL;
+
+ /* get the number of bytes */
+ z = 0;
+ y = num;
+ while (y) {
+ ++z;
+ y >>= 8;
+ }
+
+ /* handle zero */
+ if (z == 0) {
+ z = 1;
+ }
+
+ /* we need a 0x02 to indicate it's INTEGER */
+ len = 1;
+
+ /* length byte */
+ ++len;
+
+ /* bytes in value */
+ len += z;
+
+ /* see if msb is set */
+ len += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
+
+ /* return length */
+ *outlen = len;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/short_integer/der_length_short_integer.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_decode_utctime.c b/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_decode_utctime.c
new file mode 100644
index 00000000000..54fc204adee
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_decode_utctime.c
@@ -0,0 +1,127 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_utctime.c
+ ASN.1 DER, decode a UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static int char_to_int(unsigned char x)
+{
+ switch (x) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ }
+ return 100;
+}
+
+#define DECODE_V(y, max) \
+ y = char_to_int(buf[x])*10 + char_to_int(buf[x+1]); \
+ if (y >= max) return CRYPT_INVALID_PACKET; \
+ x += 2;
+
+/**
+ Decodes a UTC time structure in DER format (reads all 6 valid encoding formats)
+ @param in Input buffer
+ @param inlen Length of input buffer in octets
+ @param out [out] Destination of UTC time structure
+ @return CRYPT_OK if successful
+*/
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+ ltc_utctime *out)
+{
+ unsigned char buf[32];
+ unsigned long x;
+ int y;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ /* check header */
+ if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* decode the string */
+ for (x = 0; x < in[1]; x++) {
+ y = der_ia5_value_decode(in[x+2]);
+ if (y == -1) {
+ return CRYPT_INVALID_PACKET;
+ }
+ buf[x] = y;
+ }
+ *inlen = 2 + x;
+
+
+ /* possible encodings are
+YYMMDDhhmmZ
+YYMMDDhhmm+hh'mm'
+YYMMDDhhmm-hh'mm'
+YYMMDDhhmmssZ
+YYMMDDhhmmss+hh'mm'
+YYMMDDhhmmss-hh'mm'
+
+ So let's do a trivial decode upto [including] mm
+ */
+
+ x = 0;
+ DECODE_V(out->YY, 100);
+ DECODE_V(out->MM, 13);
+ DECODE_V(out->DD, 32);
+ DECODE_V(out->hh, 24);
+ DECODE_V(out->mm, 60);
+
+ /* clear timezone and seconds info */
+ out->off_dir = out->off_hh = out->off_mm = out->ss = 0;
+
+ /* now is it Z, +, - or 0-9 */
+ if (buf[x] == 'Z') {
+ return CRYPT_OK;
+ } else if (buf[x] == '+' || buf[x] == '-') {
+ out->off_dir = (buf[x++] == '+') ? 0 : 1;
+ DECODE_V(out->off_hh, 24);
+ DECODE_V(out->off_mm, 60);
+ return CRYPT_OK;
+ }
+
+ /* decode seconds */
+ DECODE_V(out->ss, 60);
+
+ /* now is it Z, +, - */
+ if (buf[x] == 'Z') {
+ return CRYPT_OK;
+ } else if (buf[x] == '+' || buf[x] == '-') {
+ out->off_dir = (buf[x++] == '+') ? 0 : 1;
+ DECODE_V(out->off_hh, 24);
+ DECODE_V(out->off_mm, 60);
+ return CRYPT_OK;
+ } else {
+ return CRYPT_INVALID_PACKET;
+ }
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utctime/der_decode_utctime.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_encode_utctime.c b/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_encode_utctime.c
new file mode 100644
index 00000000000..cb32dfa619b
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_encode_utctime.c
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_utctime.c
+ ASN.1 DER, encode a UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const char *baseten = "0123456789";
+
+#define STORE_V(y) \
+ out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
+ out[x++] = der_ia5_char_encode(baseten[y % 10]);
+
+/**
+ Encodes a UTC time structure in DER format
+ @param utctime The UTC time structure to encode
+ @param out The destination of the DER encoding of the UTC time structure
+ @param outlen [in/out] The length of the DER encoding
+ @return CRYPT_OK if successful
+*/
+int der_encode_utctime(ltc_utctime *utctime,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, tmplen;
+ int err;
+
+ LTC_ARGCHK(utctime != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if ((err = der_length_utctime(utctime, &tmplen)) != CRYPT_OK) {
+ return err;
+ }
+ if (tmplen > *outlen) {
+ *outlen = tmplen;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* store header */
+ out[0] = 0x17;
+
+ /* store values */
+ x = 2;
+ STORE_V(utctime->YY);
+ STORE_V(utctime->MM);
+ STORE_V(utctime->DD);
+ STORE_V(utctime->hh);
+ STORE_V(utctime->mm);
+ STORE_V(utctime->ss);
+
+ if (utctime->off_mm || utctime->off_hh) {
+ out[x++] = der_ia5_char_encode(utctime->off_dir ? '-' : '+');
+ STORE_V(utctime->off_hh);
+ STORE_V(utctime->off_mm);
+ } else {
+ out[x++] = der_ia5_char_encode('Z');
+ }
+
+ /* store length */
+ out[1] = (unsigned char)(x - 2);
+
+ /* all good let's return */
+ *outlen = x;
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utctime/der_encode_utctime.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_length_utctime.c b/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_length_utctime.c
new file mode 100644
index 00000000000..e5922b02308
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/utctime/der_length_utctime.c
@@ -0,0 +1,46 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_utctime.c
+ ASN.1 DER, get length of UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+ Gets length of DER encoding of UTCTIME
+ @param utctime The UTC time structure to get the size of
+ @param outlen [out] The length of the DER encoding
+ @return CRYPT_OK if successful
+*/
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen)
+{
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(utctime != NULL);
+
+ if (utctime->off_hh == 0 && utctime->off_mm == 0) {
+ /* we encode as YYMMDDhhmmssZ */
+ *outlen = 2 + 13;
+ } else {
+ /* we encode as YYMMDDhhmmss{+|-}hh'mm' */
+ *outlen = 2 + 17;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utctime/der_length_utctime.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_decode_utf8_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_decode_utf8_string.c
new file mode 100644
index 00000000000..9df7e2315c1
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_decode_utf8_string.c
@@ -0,0 +1,111 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_utf8_string.c
+ ASN.1 DER, encode a UTF8 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store a UTF8 STRING
+ @param in The DER encoded UTF8 STRING
+ @param inlen The size of the DER UTF8 STRING
+ @param out [out] The array of utf8s stored (one per char)
+ @param outlen [in/out] The number of utf8s stored
+ @return CRYPT_OK if successful
+*/
+int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
+ wchar_t *out, unsigned long *outlen)
+{
+ wchar_t tmp;
+ unsigned long x, y, z, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* must have header at least */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* check for 0x0C */
+ if ((in[0] & 0x1F) != 0x0C) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 1;
+
+ /* decode the length */
+ if (in[x] & 0x80) {
+ /* valid # of bytes in length are 1,2,3 */
+ y = in[x] & 0x7F;
+ if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* read the length in */
+ len = 0;
+ ++x;
+ while (y--) {
+ len = (len << 8) | in[x++];
+ }
+ } else {
+ len = in[x++] & 0x7F;
+ }
+
+ if (len + x > inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* proceed to decode */
+ for (y = 0; x < inlen; ) {
+ /* get first byte */
+ tmp = in[x++];
+
+ /* count number of bytes */
+ for (z = 0; (tmp & 0x80) && (z <= 4); z++, tmp = (tmp << 1) & 0xFF);
+
+ if (z > 4 || (x + (z - 1) > inlen)) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* decode, grab upper bits */
+ tmp >>= z;
+
+ /* grab remaining bytes */
+ if (z > 1) { --z; }
+ while (z-- != 0) {
+ if ((in[x] & 0xC0) != 0x80) {
+ return CRYPT_INVALID_PACKET;
+ }
+ tmp = (tmp << 6) | ((wchar_t)in[x++] & 0x3F);
+ }
+
+ if (y > *outlen) {
+ *outlen = y;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ out[y++] = tmp;
+ }
+ *outlen = y;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utf8/der_decode_utf8_string.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_encode_utf8_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_encode_utf8_string.c
new file mode 100644
index 00000000000..d1efb09c7b4
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_encode_utf8_string.c
@@ -0,0 +1,105 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_utf8_string.c
+ ASN.1 DER, encode a UTF8 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+ Store an UTF8 STRING
+ @param in The array of UTF8 to store (one per wchar_t)
+ @param inlen The number of UTF8 to store
+ @param out [out] The destination for the DER encoded UTF8 STRING
+ @param outlen [in/out] The max size and resulting size of the DER UTF8 STRING
+ @return CRYPT_OK if successful
+*/
+int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get the size */
+ for (x = len = 0; x < inlen; x++) {
+ if (in[x] < 0 || in[x] > 0x1FFFF) {
+ return CRYPT_INVALID_ARG;
+ }
+ len += der_utf8_charsize(in[x]);
+ }
+
+ if (len < 128) {
+ y = 2 + len;
+ } else if (len < 256) {
+ y = 3 + len;
+ } else if (len < 65536UL) {
+ y = 4 + len;
+ } else if (len < 16777216UL) {
+ y = 5 + len;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* too big? */
+ if (y > *outlen) {
+ *outlen = len;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* encode the header+len */
+ x = 0;
+ out[x++] = 0x0C;
+ if (len < 128) {
+ out[x++] = (unsigned char)len;
+ } else if (len < 256) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)len;
+ } else if (len < 65536UL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((len>>8)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else if (len < 16777216UL) {
+ out[x++] = 0x83;
+ out[x++] = (unsigned char)((len>>16)&255);
+ out[x++] = (unsigned char)((len>>8)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* store UTF8 */
+ for (y = 0; y < inlen; y++) {
+ switch (der_utf8_charsize(in[y])) {
+ case 1: out[x++] = (unsigned char)in[y]; break;
+ case 2: out[x++] = 0xC0 | ((in[y] >> 6) & 0x1F); out[x++] = 0x80 | (in[y] & 0x3F); break;
+ case 3: out[x++] = 0xE0 | ((in[y] >> 12) & 0x0F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break;
+ case 4: out[x++] = 0xF0 | ((in[y] >> 18) & 0x07); out[x++] = 0x80 | ((in[y] >> 12) & 0x3F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break;
+ }
+ }
+
+ /* retun length */
+ *outlen = x;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utf8/der_encode_utf8_string.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_length_utf8_string.c b/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_length_utf8_string.c
new file mode 100644
index 00000000000..920bd003fe5
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/utf8/der_length_utf8_string.c
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_utf8_string.c
+ ASN.1 DER, get length of UTF8 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/** Return the size in bytes of a UTF-8 character
+ @param c The UTF-8 character to measure
+ @return The size in bytes
+*/
+unsigned long der_utf8_charsize(const wchar_t c)
+{
+ if (c <= 0x7F) {
+ return 1;
+ } else if (c <= 0x7FF) {
+ return 2;
+ } else if (c <= 0xFFFF) {
+ return 3;
+ } else {
+ return 4;
+ }
+}
+
+/**
+ Gets length of DER encoding of UTF8 STRING
+ @param in The characters to measure the length of
+ @param noctets The number of octets in the string to encode
+ @param outlen [out] The length of the DER encoding for the given string
+ @return CRYPT_OK if successful
+*/
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen)
+{
+ unsigned long x, len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ len = 0;
+ for (x = 0; x < noctets; x++) {
+ if (in[x] < 0 || in[x] > 0x10FFFF) {
+ return CRYPT_INVALID_ARG;
+ }
+ len += der_utf8_charsize(in[x]);
+ }
+
+ if (len < 128) {
+ /* 0C LL DD DD DD ... */
+ *outlen = 2 + len;
+ } else if (len < 256) {
+ /* 0C 81 LL DD DD DD ... */
+ *outlen = 3 + len;
+ } else if (len < 65536UL) {
+ /* 0C 82 LL LL DD DD DD ... */
+ *outlen = 4 + len;
+ } else if (len < 16777216UL) {
+ /* 0C 83 LL LL LL DD DD DD ... */
+ *outlen = 5 + len;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/utf8/der_length_utf8_string.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.c b/crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.c
new file mode 100644
index 00000000000..3ebb8ea977f
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.c
@@ -0,0 +1,112 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_sequence_multi.c
+ ASN.1 DER, encode a Subject Public Key structure --nmav
+*/
+
+#ifdef LTC_DER
+
+/* AlgorithmIdentifier := SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm
+ * }
+ *
+ * SubjectPublicKeyInfo := SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ */
+/**
+ Encode a SEQUENCE type using a VA list
+ @param out [out] Destination for data
+ @param outlen [in/out] Length of buffer and resulting length of output
+ @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
+ unsigned int algorithm, void* public_key, unsigned long* public_key_len,
+ unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len)
+{
+ int err, len;
+ oid_st oid;
+ unsigned char *tmpbuf;
+ unsigned long tmpoid[16];
+ ltc_asn1_list alg_id[2];
+ ltc_asn1_list subject_pubkey[2];
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != 0);
+
+ err = pk_get_oid(algorithm, &oid);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ /* see if the OpenSSL DER format RSA public key will work */
+ tmpbuf = XCALLOC(1, MAX_RSA_SIZE*8);
+ if (tmpbuf == NULL) {
+ err = CRYPT_MEM;
+ goto LBL_ERR;
+ }
+
+ /* this includes the internal hash ID and optional params (NULL in this case) */
+ LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
+ LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, parameters_len);
+
+ /* the actual format of the SSL DER key is odd, it stores a RSAPublicKey in a **BIT** string ... so we have to extract it
+ then proceed to convert bit to octet
+ */
+ LTC_SET_ASN1(subject_pubkey, 0, LTC_ASN1_SEQUENCE, alg_id, 2);
+ LTC_SET_ASN1(subject_pubkey, 1, LTC_ASN1_BIT_STRING, tmpbuf, MAX_RSA_SIZE*8);
+
+ err=der_decode_sequence(in, inlen, subject_pubkey, 2UL);
+ if (err != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ len = subject_pubkey[1].size/8;
+ if (*public_key_len > len) {
+ memcpy(public_key, subject_pubkey[1].data, len);
+ *public_key_len = len;
+ } else {
+ *public_key_len = len;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ err = CRYPT_OK;
+
+LBL_ERR:
+
+ XFREE(tmpbuf);
+
+ return err;
+}
+
+#endif
+
+
diff --git a/crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_encode_subject_public_key_info.c b/crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_encode_subject_public_key_info.c
new file mode 100644
index 00000000000..4c7e966491d
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/asn1/der/x509/der_encode_subject_public_key_info.c
@@ -0,0 +1,83 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_sequence_multi.c
+ ASN.1 DER, encode a Subject Public Key structure --nmav
+*/
+
+#ifdef LTC_DER
+
+/* AlgorithmIdentifier := SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm
+ * }
+ *
+ * SubjectPublicKeyInfo := SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ */
+/**
+ Encode a SEQUENCE type using a VA list
+ @param out [out] Destination for data
+ @param outlen [in/out] Length of buffer and resulting length of output
+ @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
+ unsigned int algorithm, void* public_key, unsigned long public_key_len,
+ unsigned long parameters_type, void* parameters, unsigned long parameters_len)
+{
+ int err;
+ ltc_asn1_list alg_id[2];
+ oid_st oid;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ err = pk_get_oid(algorithm, &oid);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ alg_id[0].data = oid.OID;
+ alg_id[0].size = oid.OIDlen;
+ alg_id[0].type = LTC_ASN1_OBJECT_IDENTIFIER;
+
+ alg_id[1].data = parameters;
+ alg_id[1].size = parameters_len;
+ alg_id[1].type = parameters_type;
+
+ return der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SEQUENCE, (unsigned long)sizeof(alg_id)/sizeof(alg_id[0]), alg_id,
+ LTC_ASN1_BIT_STRING, (unsigned long)(public_key_len*8), public_key,
+ LTC_ASN1_EOL, 0UL, NULL);
+
+}
+
+#endif
+
+
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_export.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_export.c
new file mode 100644
index 00000000000..5a2d5df87c7
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_export.c
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file dsa_export.c
+ DSA implementation, export key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+ Export a DSA key to a binary packet
+ @param out [out] Where to store the packet
+ @param outlen [in/out] The max size and resulting size of the packet
+ @param type The type of key to export (PK_PRIVATE or PK_PUBLIC)
+ @param key The key to export
+ @return CRYPT_OK if successful
+*/
+int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key)
+{
+ unsigned long zero=0;
+ int err;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* can we store the static header? */
+ if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
+ return CRYPT_PK_TYPE_MISMATCH;
+ }
+
+ if (type != PK_PUBLIC && type != PK_PRIVATE) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* This encoding is different from the one in original
+ * libtomcrypt. It uses a compatible encoding with gnutls
+ * and openssl
+ */
+ if (type == PK_PRIVATE) {
+ return der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+ LTC_ASN1_INTEGER, 1UL, &key->p,
+ LTC_ASN1_INTEGER, 1UL, &key->q,
+ LTC_ASN1_INTEGER, 1UL, &key->g,
+ LTC_ASN1_INTEGER, 1UL, &key->y,
+ LTC_ASN1_INTEGER, 1UL, &key->x,
+ LTC_ASN1_EOL, 0UL, NULL);
+ } else {
+ unsigned long tmplen = (mp_count_bits(&key->y)/8)+8;
+ unsigned char* tmp = XMALLOC(tmplen);
+ ltc_asn1_list int_list[3];
+
+ if (tmp == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = der_encode_integer(&key->y, tmp, &tmplen);
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+
+ int_list[0].data = &key->p;
+ int_list[0].size = 1UL;
+ int_list[0].type = LTC_ASN1_INTEGER;
+ int_list[1].data = &key->q;
+ int_list[1].size = 1UL;
+ int_list[1].type = LTC_ASN1_INTEGER;
+ int_list[2].data = &key->g;
+ int_list[2].size = 1UL;
+ int_list[2].type = LTC_ASN1_INTEGER;
+
+ err = der_encode_subject_public_key_info(out, outlen,
+ PKA_DSA, tmp, tmplen,
+ LTC_ASN1_SEQUENCE, int_list, sizeof(int_list)/sizeof(int_list[0]));
+
+error:
+ XFREE(tmp);
+ return err;
+ }
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_export.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_free.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_free.c
new file mode 100644
index 00000000000..37a330d14e8
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_free.c
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file dsa_free.c
+ DSA implementation, free a DSA key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+ Free a DSA key
+ @param key The key to free from memory
+*/
+void dsa_free(dsa_key *key)
+{
+ LTC_ARGCHKVD(key != NULL);
+ mp_clear_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL);
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_free.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_import.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_import.c
new file mode 100644
index 00000000000..c6a1f6f6037
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_import.c
@@ -0,0 +1,101 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file dsa_import.c
+ DSA implementation, import a DSA key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+ Import a DSA key
+ @param in The binary packet to import from
+ @param inlen The length of the binary packet
+ @param key [out] Where to store the imported key
+ @return CRYPT_OK if successful, upon error this function will free all allocated memory
+*/
+int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
+{
+ int err;
+ unsigned long zero = 0;
+ unsigned char* tmpbuf = NULL;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* init key */
+ if (mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ /* get key type */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+ LTC_ASN1_INTEGER, 1UL, &key->p,
+ LTC_ASN1_INTEGER, 1UL, &key->q,
+ LTC_ASN1_INTEGER, 1UL, &key->g,
+ LTC_ASN1_INTEGER, 1UL, &key->y,
+ LTC_ASN1_INTEGER, 1UL, &key->x,
+ LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) {
+ key->type = PK_PRIVATE;
+ } else { /* public */
+ ltc_asn1_list params[3];
+ unsigned long tmpbuf_len = MAX_RSA_SIZE*8;
+
+ LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, &key->p, 1UL);
+ LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, &key->q, 1UL);
+ LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, &key->g, 1UL);
+
+ tmpbuf = XCALLOC(1, tmpbuf_len);
+ if (tmpbuf == NULL) {
+ err = CRYPT_MEM;
+ goto LBL_ERR;
+ }
+
+ err = der_decode_subject_public_key_info(in, inlen,
+ PKA_DSA, tmpbuf, &tmpbuf_len,
+ LTC_ASN1_SEQUENCE, params, 3);
+ if (err != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ if ((err=der_decode_integer(tmpbuf, tmpbuf_len, &key->y)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ XFREE(tmpbuf);
+ key->type = PK_PUBLIC;
+ }
+
+ key->qord = mp_unsigned_bin_size(&key->q);
+
+ if (key->qord >= LTC_MDSA_MAX_GROUP || key->qord <= 15 ||
+ (unsigned long)key->qord >= mp_unsigned_bin_size(&key->p) || (mp_unsigned_bin_size(&key->p) - key->qord) >= LTC_MDSA_DELTA) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ return CRYPT_OK;
+
+LBL_ERR:
+ XFREE(tmpbuf);
+ mp_clear_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_import.c,v $ */
+/* $Revision: 1.14 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_make_key.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_make_key.c
new file mode 100644
index 00000000000..eab5d155899
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_make_key.c
@@ -0,0 +1,125 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file dsa_make_key.c
+ DSA implementation, generate a DSA key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+ Create a DSA key
+ @param group_size Size of the multiplicative group (octets)
+ @param modulus_size Size of the modulus (octets)
+ @param key [out] Where to store the created key
+ @return CRYPT_OK if successful, upon error this function will free all allocated memory
+*/
+int dsa_make_key(int group_size, int modulus_size, dsa_key *key)
+{
+ mp_int tmp, tmp2;
+ int err, res;
+ unsigned char *buf;
+
+ LTC_ARGCHK(key != NULL);
+
+ /* check size */
+ if (group_size >= LTC_MDSA_MAX_GROUP || group_size <= 15 ||
+ group_size >= modulus_size || (modulus_size - group_size) >= LTC_MDSA_DELTA) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* allocate ram */
+ buf = XMALLOC(LTC_MDSA_DELTA);
+ if (buf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* init mp_ints */
+ if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+
+ /* make our prime q */
+ if ((err = rand_prime(&key->q, group_size)) != CRYPT_OK) { goto error; }
+
+ /* double q */
+ if ((err = mp_add(&key->q, &key->q, &tmp)) != CRYPT_OK) { goto error; }
+
+ /* now make a random string and multply it against q */
+ get_random_bytes(buf+1, modulus_size - group_size);
+
+ /* force magnitude */
+ buf[0] |= 0xC0;
+
+ /* force even */
+ buf[modulus_size - group_size - 1] &= ~1;
+
+ if ((err = mp_read_unsigned_bin(&tmp2, buf, modulus_size - group_size)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mul(&key->q, &tmp2, &key->p)) != CRYPT_OK) { goto error; }
+ if ((err = mp_add_d(&key->p, 1, &key->p)) != CRYPT_OK) { goto error; }
+
+ /* now loop until p is prime */
+ for (;;) {
+ if ((err = mp_prime_is_prime(&key->p, 8, &res)) != CRYPT_OK) { goto error; }
+ if (res == LTC_MP_YES) break;
+
+ /* add 2q to p and 2 to tmp2 */
+ if ((err = mp_add(&tmp, &key->p, &key->p)) != CRYPT_OK) { goto error; }
+ if ((err = mp_add_d(&tmp2, 2, &tmp2)) != CRYPT_OK) { goto error; }
+ }
+
+ /* now p = (q * tmp2) + 1 is prime, find a value g for which g^tmp2 != 1 */
+ mp_set(&key->g, 1);
+
+ do {
+ if ((err = mp_add_d(&key->g, 1, &key->g)) != CRYPT_OK) { goto error; }
+ if ((err = mp_exptmod(&key->g, &tmp2, &key->p, &tmp)) != CRYPT_OK) { goto error; }
+ } while (mp_cmp_d(&tmp, 1) == LTC_MP_EQ);
+
+ /* at this point tmp generates a group of order q mod p */
+ mp_exch(&tmp, &key->g);
+
+ /* so now we have our DH structure, generator g, order q, modulus p
+ Now we need a random exponent [mod q] and it's power g^x mod p
+ */
+ do {
+ get_random_bytes(buf, group_size);
+
+ if ((err = mp_read_unsigned_bin(&key->x, buf, group_size)) != CRYPT_OK) { goto error; }
+ } while (mp_cmp_d(&key->x, 1) != LTC_MP_GT);
+ if ((err = mp_exptmod(&key->g, &key->x, &key->p, &key->y)) != CRYPT_OK) { goto error; }
+
+ key->type = PK_PRIVATE;
+ key->qord = group_size;
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, LTC_MDSA_DELTA);
+#endif
+
+ err = CRYPT_OK;
+ goto done;
+error:
+ mp_clear_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL);
+done:
+ mp_clear_multi(&tmp, &tmp2, NULL);
+ XFREE(buf);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_make_key.c,v $ */
+/* $Revision: 1.12 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_sign_hash.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_sign_hash.c
new file mode 100644
index 00000000000..6f4dad8d3e6
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_sign_hash.c
@@ -0,0 +1,147 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file dsa_sign_hash.c
+ DSA implementation, sign a hash, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+ Sign a hash with DSA
+ @param in The hash to sign
+ @param inlen The length of the hash to sign
+ @param r The "r" integer of the signature (caller must initialize with mp_init() first)
+ @param s The "s" integer of the signature (caller must initialize with mp_init() first)
+ @param key A private DSA key
+ @return CRYPT_OK if successful
+*/
+int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen,
+ mp_int_t r, mp_int_t s,
+ dsa_key *key)
+{
+ mp_int k, kinv, tmp;
+ unsigned char *buf;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(r != NULL);
+ LTC_ARGCHK(s != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (key->type != PK_PRIVATE) {
+ return CRYPT_PK_NOT_PRIVATE;
+ }
+
+ /* check group order size */
+ if (key->qord >= LTC_MDSA_MAX_GROUP) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ buf = XMALLOC(LTC_MDSA_MAX_GROUP);
+ if (buf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* Init our temps */
+ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; }
+
+retry:
+
+ do {
+ /* gen random k */
+ get_random_bytes(buf, key->qord);
+
+ /* read k */
+ if ((err = mp_read_unsigned_bin(&k, buf, key->qord)) != CRYPT_OK) { goto error; }
+
+ /* k > 1 ? */
+ if (mp_cmp_d(&k, 1) != LTC_MP_GT) { goto retry; }
+
+ /* test gcd */
+ if ((err = mp_gcd(&k, &key->q, &tmp)) != CRYPT_OK) { goto error; }
+ } while (mp_cmp_d(&tmp, 1) != LTC_MP_EQ);
+
+ /* now find 1/k mod q */
+ if ((err = mp_invmod(&k, &key->q, &kinv)) != CRYPT_OK) { goto error; }
+
+ /* now find r = g^k mod p mod q */
+ if ((err = mp_exptmod(&key->g, &k, &key->p, r)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mod(r, &key->q, r)) != CRYPT_OK) { goto error; }
+
+ if (mp_iszero(r) == LTC_MP_YES) { goto retry; }
+
+ /* now find s = (in + xr)/k mod q */
+ if ((err = mp_read_unsigned_bin(&tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mul(&key->x, r, s)) != CRYPT_OK) { goto error; }
+ if ((err = mp_add(s, &tmp, s)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mulmod(s, &kinv, &key->q, s)) != CRYPT_OK) { goto error; }
+
+ if (mp_iszero(s) == LTC_MP_YES) { goto retry; }
+
+ err = CRYPT_OK;
+error:
+ mp_clear_multi(&k, &kinv, &tmp, NULL);
+ERRBUF:
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, LTC_MDSA_MAX_GROUP);
+#endif
+ XFREE(buf);
+ return err;
+}
+
+/**
+ Sign a hash with DSA
+ @param in The hash to sign
+ @param inlen The length of the hash to sign
+ @param out [out] Where to store the signature
+ @param outlen [in/out] The max size and resulting size of the signature
+ @param key A private DSA key
+ @return CRYPT_OK if successful
+*/
+int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ dsa_key *key)
+{
+ mp_int r, s;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (mp_init_multi(&r, &s, NULL) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ if ((err = dsa_sign_hash_raw(in, inlen, &r, &s, key)) != CRYPT_OK) {
+ goto error;
+ }
+
+ err = der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_INTEGER, 1UL, &r,
+ LTC_ASN1_INTEGER, 1UL, &s,
+ LTC_ASN1_EOL, 0UL, NULL);
+
+error:
+ mp_clear_multi(&r, &s, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_sign_hash.c,v $ */
+/* $Revision: 1.14 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_hash.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_hash.c
new file mode 100644
index 00000000000..3a82d1bc420
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_hash.c
@@ -0,0 +1,126 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file dsa_verify_hash.c
+ DSA implementation, verify a signature, Tom St Denis
+*/
+
+
+#ifdef LTC_MDSA
+
+/**
+ Verify a DSA signature
+ @param r DSA "r" parameter
+ @param s DSA "s" parameter
+ @param hash The hash that was signed
+ @param hashlen The length of the hash that was signed
+ @param stat [out] The result of the signature verification, 1==valid, 0==invalid
+ @param key The corresponding public DH key
+ @return CRYPT_OK if successful (even if the signature is invalid)
+*/
+int dsa_verify_hash_raw( mp_int_t r, mp_int_t s,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key)
+{
+ mp_int w, v, u1, u2;
+ int err;
+
+ LTC_ARGCHK(r != NULL);
+ LTC_ARGCHK(s != NULL);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* default to invalid signature */
+ *stat = 0;
+
+ /* init our variables */
+ if ((err = mp_init_multi(&w, &v, &u1, &u2, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* neither r or s can be null or >q*/
+ if (mp_iszero(r) == LTC_MP_YES || mp_iszero(s) == LTC_MP_YES || mp_cmp(r, &key->q) != LTC_MP_LT || mp_cmp(s, &key->q) != LTC_MP_LT) {
+ err = CRYPT_INVALID_PACKET;
+ goto error;
+ }
+
+ /* w = 1/s mod q */
+ if ((err = mp_invmod(s, &key->q, &w)) != CRYPT_OK) { goto error; }
+
+ /* u1 = m * w mod q */
+ if ((err = mp_read_unsigned_bin(&u1, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mulmod(&u1, &w, &key->q, &u1)) != CRYPT_OK) { goto error; }
+
+ /* u2 = r*w mod q */
+ if ((err = mp_mulmod(r, &w, &key->q, &u2)) != CRYPT_OK) { goto error; }
+
+ /* v = g^u1 * y^u2 mod p mod q */
+ if ((err = mp_exptmod(&key->g, &u1, &key->p, &u1)) != CRYPT_OK) { goto error; }
+ if ((err = mp_exptmod(&key->y, &u2, &key->p, &u2)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mulmod(&u1, &u2, &key->p, &v)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mod(&v, &key->q, &v)) != CRYPT_OK) { goto error; }
+
+ /* if r = v then we're set */
+ if (mp_cmp(r, &v) == LTC_MP_EQ) {
+ *stat = 1;
+ }
+
+ err = CRYPT_OK;
+error:
+ mp_clear_multi(&w, &v, &u1, &u2, NULL);
+ return err;
+}
+
+/**
+ Verify a DSA signature
+ @param sig The signature
+ @param siglen The length of the signature (octets)
+ @param hash The hash that was signed
+ @param hashlen The length of the hash that was signed
+ @param stat [out] The result of the signature verification, 1==valid, 0==invalid
+ @param key The corresponding public DH key
+ @return CRYPT_OK if successful (even if the signature is invalid)
+*/
+int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key)
+{
+ int err;
+ mp_int r, s;
+
+ if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) {
+ return CRYPT_MEM;
+ }
+
+ /* decode the sequence */
+ if ((err = der_decode_sequence_multi(sig, siglen,
+ LTC_ASN1_INTEGER, 1UL, &r,
+ LTC_ASN1_INTEGER, 1UL, &s,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* do the op */
+ err = dsa_verify_hash_raw(&r, &s, hash, hashlen, stat, key);
+
+LBL_ERR:
+ mp_clear_multi(&r, &s, NULL);
+ return err;
+}
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_verify_hash.c,v $ */
+/* $Revision: 1.15 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_key.c b/crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_key.c
new file mode 100644
index 00000000000..71635d25912
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/dsa/dsa_verify_key.c
@@ -0,0 +1,100 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file dsa_verify_key.c
+ DSA implementation, verify a key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+ Verify a DSA key for validity
+ @param key The key to verify
+ @param stat [out] Result of test, 1==valid, 0==invalid
+ @return CRYPT_OK if successful
+*/
+int dsa_verify_key(dsa_key *key, int *stat)
+{
+ mp_int tmp, tmp2;
+ int res, err;
+
+ LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(stat != NULL);
+
+ /* default to an invalid key */
+ *stat = 0;
+
+ /* first make sure key->q and key->p are prime */
+ if ((err = mp_prime_is_prime(&key->q, 8, &res)) != CRYPT_OK) {
+ return err;
+ }
+ if (res == 0) {
+ return CRYPT_OK;
+ }
+
+ if ((err = mp_prime_is_prime(&key->p, 8, &res)) != CRYPT_OK) {
+ return err;
+ }
+ if (res == 0) {
+ return CRYPT_OK;
+ }
+
+ /* now make sure that g is not -1, 0 or 1 and <p */
+ if (mp_cmp_d(&key->g, 0) == LTC_MP_EQ || mp_cmp_d(&key->g, 1) == LTC_MP_EQ) {
+ return CRYPT_OK;
+ }
+ if ((err = mp_init_multi(&tmp, &tmp2, NULL)) != CRYPT_OK) { return err; }
+ if ((err = mp_sub_d(&key->p, 1, &tmp)) != CRYPT_OK) { goto error; }
+ if (mp_cmp(&tmp, &key->g) == LTC_MP_EQ || mp_cmp(&key->g, &key->p) != LTC_MP_LT) {
+ err = CRYPT_OK;
+ goto error;
+ }
+
+ /* 1 < y < p-1 */
+ if (!(mp_cmp_d(&key->y, 1) == LTC_MP_GT && mp_cmp(&key->y, &tmp) == LTC_MP_LT)) {
+ err = CRYPT_OK;
+ goto error;
+ }
+
+ /* now we have to make sure that g^q = 1, and that p-1/q gives 0 remainder */
+ if ((err = mp_div(&tmp, &key->q, &tmp, &tmp2)) != CRYPT_OK) { goto error; }
+ if (mp_iszero(&tmp2) != LTC_MP_YES) {
+ err = CRYPT_OK;
+ goto error;
+ }
+
+ if ((err = mp_exptmod(&key->g, &key->q, &key->p, &tmp)) != CRYPT_OK) { goto error; }
+ if (mp_cmp_d(&tmp, 1) != LTC_MP_EQ) {
+ err = CRYPT_OK;
+ goto error;
+ }
+
+ /* now we have to make sure that y^q = 1, this makes sure y \in g^x mod p */
+ if ((err = mp_exptmod(&key->y, &key->q, &key->p, &tmp)) != CRYPT_OK) { goto error; }
+ if (mp_cmp_d(&tmp, 1) != LTC_MP_EQ) {
+ err = CRYPT_OK;
+ goto error;
+ }
+
+ /* at this point we are out of tests ;-( */
+ err = CRYPT_OK;
+ *stat = 1;
+error:
+ mp_clear_multi(&tmp, &tmp2, NULL);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/dsa/dsa_verify_key.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_i2osp.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_i2osp.c
new file mode 100644
index 00000000000..70294a505e0
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_i2osp.c
@@ -0,0 +1,51 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file pkcs_1_i2osp.c
+ Integer to Octet I2OSP, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/* always stores the same # of bytes, pads with leading zero bytes
+ as required
+ */
+
+/**
+ LTC_PKCS #1 Integer to binary
+ @param n The integer to store
+ @param modulus_len The length of the RSA modulus
+ @param out [out] The destination for the integer
+ @return CRYPT_OK if successful
+*/
+int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out)
+{
+ unsigned long size;
+
+ size = mp_unsigned_bin_size(n);
+
+ if (size > modulus_len) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ /* store it */
+ zeromem(out, modulus_len);
+ return mp_to_unsigned_bin(n, out+(modulus_len-size));
+}
+
+#endif /* LTC_PKCS_1 */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_i2osp.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_mgf1.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_mgf1.c
new file mode 100644
index 00000000000..bfa3e7e9192
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_mgf1.c
@@ -0,0 +1,91 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+
+/**
+ @file pkcs_1_mgf1.c
+ The Mask Generation Function (MGF1) for LTC_PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ Perform LTC_PKCS #1 MGF1 (internal)
+ @param seed The seed for MGF1
+ @param seedlen The length of the seed
+ @param hash The desired hash
+ @param mask [out] The destination
+ @param masklen The length of the mask desired
+ @return CRYPT_OK if successful
+*/
+int pkcs_1_mgf1(const struct algo_properties_st *hash,
+ const unsigned char *seed, unsigned long seedlen,
+ unsigned char *mask, unsigned long masklen)
+{
+ unsigned long hLen, x;
+ ulong32 counter;
+ int err;
+ unsigned char *buf;
+
+ LTC_ARGCHK(seed != NULL);
+ LTC_ARGCHK(mask != NULL);
+
+ /* ensure valid hash */
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* get hash output size */
+ hLen = hash->digest_size;
+
+ /* allocate memory */
+ buf = XMALLOC(hLen);
+ if (buf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* start counter */
+ counter = 0;
+
+ while (masklen > 0) {
+ /* handle counter */
+ STORE32H(counter, buf);
+ ++counter;
+
+ err = hash_memory_multi(hash, buf, &hLen, seed, seedlen, buf, (unsigned long) 4, NULL, 0);
+ if (err != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* store it */
+ for (x = 0; x < hLen && masklen > 0; x++, masklen--) {
+ *mask++ = buf[x];
+ }
+ }
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(buf, hLen);
+#endif
+
+ XFREE(buf);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_decode.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_decode.c
new file mode 100644
index 00000000000..04833ff03b1
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_decode.c
@@ -0,0 +1,192 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+
+/**
+ @file pkcs_1_oaep_decode.c
+ OAEP Padding for LTC_PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ LTC_PKCS #1 v2.00 OAEP decode
+ @param msg The encoded data to decode
+ @param msglen The length of the encoded data (octets)
+ @param lparam The session or system data (can be NULL)
+ @param lparamlen The length of the lparam
+ @param modulus_bitlen The bit length of the RSA modulus
+ @param hash The desired hash
+ @param out [out] Destination of decoding
+ @param outlen [in/out] The max size and resulting size of the decoding
+ @param res [out] Result of decoding, 1==valid, 0==invalid
+ @return CRYPT_OK if successful (even if invalid)
+*/
+int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, const struct algo_properties_st *hash,
+ unsigned char *out, unsigned long *outlen,
+ int *res)
+{
+ unsigned char *DB, *seed, *mask;
+ unsigned long hLen, x, y, modulus_len;
+ int err;
+
+ LTC_ARGCHK(msg != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(res != NULL);
+
+ /* default to invalid packet */
+ *res = 0;
+
+ /* test valid hash */
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ hLen = hash->digest_size;
+ modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* test hash/message size */
+ if ((2*hLen >= (modulus_len - 2)) || (msglen != modulus_len)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* allocate ram for DB/mask/salt of size modulus_len */
+ DB = XMALLOC(modulus_len);
+ mask = XMALLOC(modulus_len);
+ seed = XMALLOC(hLen);
+ if (DB == NULL || mask == NULL || seed == NULL) {
+ if (DB != NULL) {
+ XFREE(DB);
+ }
+ if (mask != NULL) {
+ XFREE(mask);
+ }
+ if (seed != NULL) {
+ XFREE(seed);
+ }
+ return CRYPT_MEM;
+ }
+
+ /* ok so it's now in the form
+
+ 0x00 || maskedseed || maskedDB
+
+ 1 || hLen || modulus_len - hLen - 1
+
+ */
+
+ /* must have leading 0x00 byte */
+ if (msg[0] != 0x00) {
+ err = CRYPT_OK;
+ goto LBL_ERR;
+ }
+
+ /* now read the masked seed */
+ x = 1;
+ XMEMCPY(seed, msg + x, hLen);
+ x += hLen;
+
+ /* now read the masked DB */
+ XMEMCPY(DB, msg + x, modulus_len - hLen - 1);
+ x += modulus_len - hLen - 1;
+
+ /* compute MGF1 of maskedDB (hLen) */
+ if ((err = pkcs_1_mgf1(hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* XOR against seed */
+ for (y = 0; y < hLen; y++) {
+ seed[y] ^= mask[y];
+ }
+
+ /* compute MGF1 of seed (k - hlen - 1) */
+ if ((err = pkcs_1_mgf1(hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* xor against DB */
+ for (y = 0; y < (modulus_len - hLen - 1); y++) {
+ DB[y] ^= mask[y];
+ }
+
+ /* now DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
+
+ /* compute lhash and store it in seed [reuse temps!] */
+ x = modulus_len;
+ if (lparam != NULL) {
+ if ((err = hash_memory(hash, lparam, lparamlen, seed, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* can't pass hash_memory a NULL so use DB with zero length */
+ if ((err = hash_memory(hash, DB, 0, seed, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* compare the lhash'es */
+ if (XMEMCMP(seed, DB, hLen) != 0) {
+ err = CRYPT_OK;
+ goto LBL_ERR;
+ }
+
+ /* now zeroes before a 0x01 */
+ for (x = hLen; x < (modulus_len - hLen - 1) && DB[x] == 0x00; x++) {
+ /* step... */
+ }
+
+ /* error out if wasn't 0x01 */
+ if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* rest is the message (and skip 0x01) */
+ if ((modulus_len - hLen - 1 - ++x) > *outlen) {
+ *outlen = modulus_len - hLen - 1 - x;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ /* copy message */
+ *outlen = modulus_len - hLen - 1 - x;
+ XMEMCPY(out, DB + x, modulus_len - hLen - 1 - x);
+ x += modulus_len - hLen - 1;
+
+ /* valid packet */
+ *res = 1;
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(DB, modulus_len);
+ zeromem(seed, hLen);
+ zeromem(mask, modulus_len);
+#endif
+
+ XFREE(seed);
+ XFREE(mask);
+ XFREE(DB);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_encode.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_encode.c
new file mode 100644
index 00000000000..ab75f73d7d0
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_oaep_encode.c
@@ -0,0 +1,164 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+
+/**
+ @file pkcs_1_oaep_encode.c
+ OAEP Padding for LTC_PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ LTC_PKCS #1 v2.00 OAEP encode
+ @param msg The data to encode
+ @param msglen The length of the data to encode (octets)
+ @param lparam A session or system parameter (can be NULL)
+ @param lparamlen The length of the lparam data
+ @param modulus_bitlen The bit length of the RSA modulus
+ @param hash The desired hash
+ @param out [out] The destination for the encoded data
+ @param outlen [in/out] The max size and resulting size of the encoded data
+ @return CRYPT_OK if successful
+*/
+int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, const struct algo_properties_st *hash,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned char *DB, *seed, *mask;
+ unsigned long hLen, x, y, modulus_len;
+ int err;
+
+ LTC_ARGCHK(msg != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* test valid hash */
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ hLen = hash->digest_size;
+ modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* test message size */
+ if ((2*hLen >= (modulus_len - 2)) || (msglen > (modulus_len - 2*hLen - 2))) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* allocate ram for DB/mask/salt of size modulus_len */
+ DB = XMALLOC(modulus_len);
+ mask = XMALLOC(modulus_len);
+ seed = XMALLOC(hLen);
+ if (DB == NULL || mask == NULL || seed == NULL) {
+ if (DB != NULL) {
+ XFREE(DB);
+ }
+ if (mask != NULL) {
+ XFREE(mask);
+ }
+ if (seed != NULL) {
+ XFREE(seed);
+ }
+ return CRYPT_MEM;
+ }
+
+ /* get lhash */
+ /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
+ x = modulus_len;
+ if (lparam != NULL) {
+ if ((err = hash_memory(hash, lparam, lparamlen, DB, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* can't pass hash_memory a NULL so use DB with zero length */
+ if ((err = hash_memory(hash, DB, 0, DB, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* append PS then 0x01 (to lhash) */
+ x = hLen;
+ y = modulus_len - msglen - 2*hLen - 2;
+ XMEMSET(DB+x, 0, y);
+ x += y;
+
+ /* 0x01 byte */
+ DB[x++] = 0x01;
+
+ /* message (length = msglen) */
+ XMEMCPY(DB+x, msg, msglen);
+ x += msglen;
+
+ /* now choose a random seed */
+ get_random_bytes(seed, hLen);
+
+ /* compute MGF1 of seed (k - hlen - 1) */
+ if ((err = pkcs_1_mgf1(hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* xor against DB */
+ for (y = 0; y < (modulus_len - hLen - 1); y++) {
+ DB[y] ^= mask[y];
+ }
+
+ /* compute MGF1 of maskedDB (hLen) */
+ if ((err = pkcs_1_mgf1(hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* XOR against seed */
+ for (y = 0; y < hLen; y++) {
+ seed[y] ^= mask[y];
+ }
+
+ /* create string of length modulus_len */
+ if (*outlen < modulus_len) {
+ *outlen = modulus_len;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ /* start output which is 0x00 || maskedSeed || maskedDB */
+ x = 0;
+ out[x++] = 0x00;
+ XMEMCPY(out+x, seed, hLen);
+ x += hLen;
+ XMEMCPY(out+x, DB, modulus_len - hLen - 1);
+ x += modulus_len - hLen - 1;
+
+ *outlen = x;
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(DB, modulus_len);
+ zeromem(seed, hLen);
+ zeromem(mask, modulus_len);
+#endif
+
+ XFREE(seed);
+ XFREE(mask);
+ XFREE(DB);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_encode.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_os2ip.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_os2ip.c
new file mode 100644
index 00000000000..513abb69f84
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_os2ip.c
@@ -0,0 +1,36 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file pkcs_1_os2ip.c
+ Octet to Integer OS2IP, Tom St Denis
+*/
+#ifdef LTC_PKCS_1
+
+/**
+ Read a binary string into an mp_int
+ @param n [out] The mp_int destination
+ @param in The binary string to read
+ @param inlen The length of the binary string
+ @return CRYPT_OK if successful
+*/
+int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen)
+{
+ return mp_read_unsigned_bin(n, in, inlen);
+}
+
+#endif /* LTC_PKCS_1 */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_os2ip.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_decode.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_decode.c
new file mode 100644
index 00000000000..789d12d9d42
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_decode.c
@@ -0,0 +1,168 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+
+/**
+ @file pkcs_1_pss_decode.c
+ LTC_PKCS #1 PSS Signature Padding, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ LTC_PKCS #1 v2.00 PSS decode
+ @param msghash The hash to verify
+ @param msghashlen The length of the hash (octets)
+ @param sig The signature data (encoded data)
+ @param siglen The length of the signature data (octets)
+ @param saltlen The length of the salt used (octets)
+ @param hash_algo The desired hash
+ @param modulus_bitlen The bit length of the RSA modulus
+ @param res [out] The result of the comparison, 1==valid, 0==invalid
+ @return CRYPT_OK if successful (even if the comparison failed)
+*/
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+ const unsigned char *sig, unsigned long siglen,
+ unsigned long saltlen, const struct algo_properties_st *hash_algo,
+ unsigned long modulus_bitlen, int *res)
+{
+ unsigned char *DB, *mask, *salt, *hash;
+ unsigned long x, y, hLen, modulus_len;
+ int err;
+
+ LTC_ARGCHK(msghash != NULL);
+ LTC_ARGCHK(res != NULL);
+
+ /* default to invalid */
+ *res = 0;
+
+ /* ensure hash is valid */
+ if ((err = hash_is_valid(hash_algo)) != CRYPT_OK) {
+ return err;
+ }
+
+ hLen = hash_algo->digest_size;
+ modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* check sizes */
+ if ((saltlen > modulus_len) ||
+ (modulus_len < hLen + saltlen + 2) || (siglen != modulus_len)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* allocate ram for DB/mask/salt/hash of size modulus_len */
+ DB = XMALLOC(modulus_len);
+ mask = XMALLOC(modulus_len);
+ salt = XMALLOC(modulus_len);
+ hash = XMALLOC(modulus_len);
+ if (DB == NULL || mask == NULL || salt == NULL || hash == NULL) {
+ if (DB != NULL) {
+ XFREE(DB);
+ }
+ if (mask != NULL) {
+ XFREE(mask);
+ }
+ if (salt != NULL) {
+ XFREE(salt);
+ }
+ if (hash != NULL) {
+ XFREE(hash);
+ }
+ return CRYPT_MEM;
+ }
+
+ /* ensure the 0xBC byte */
+ if (sig[siglen-1] != 0xBC) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* copy out the DB */
+ x = 0;
+ XMEMCPY(DB, sig + x, modulus_len - hLen - 1);
+ x += modulus_len - hLen - 1;
+
+ /* copy out the hash */
+ XMEMCPY(hash, sig + x, hLen);
+ x += hLen;
+
+ /* check the MSB */
+ if ((sig[0] & ~(0xFF >> ((modulus_len<<3) - (modulus_bitlen-1)))) != 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* generate mask of length modulus_len - hLen - 1 from hash */
+ if ((err = pkcs_1_mgf1(hash_algo, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* xor against DB */
+ for (y = 0; y < (modulus_len - hLen - 1); y++) {
+ DB[y] ^= mask[y];
+ }
+
+ /* now clear the first byte [make sure smaller than modulus] */
+ DB[0] &= 0xFF >> ((modulus_len<<3) - (modulus_bitlen-1));
+
+ /* DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */
+
+ /* check for zeroes and 0x01 */
+ for (x = 0; x < modulus_len - saltlen - hLen - 2; x++) {
+ if (DB[x] != 0x00) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ }
+
+ /* check for the 0x01 */
+ if (DB[x++] != 0x01) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ zeromem(mask, 8);
+
+ /* M = (eight) 0x00 || msghash || salt, mask = H(M) */
+ err = hash_memory_multi(hash_algo, mask, &hLen, mask, (unsigned long)8, msghash, (unsigned long)msghashlen, DB+x, (unsigned long)saltlen, NULL, 0);
+ if (err != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* mask == hash means valid signature */
+ if (XMEMCMP(mask, hash, hLen) == 0) {
+ *res = 1;
+ }
+
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(DB, modulus_len);
+ zeromem(mask, modulus_len);
+ zeromem(salt, modulus_len);
+ zeromem(hash, modulus_len);
+#endif
+
+ XFREE(hash);
+ XFREE(salt);
+ XFREE(mask);
+ XFREE(DB);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c,v $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_encode.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_encode.c
new file mode 100644
index 00000000000..d3ce3d9c012
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_pss_encode.c
@@ -0,0 +1,157 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+
+/**
+ @file pkcs_1_pss_encode.c
+ LTC_PKCS #1 PSS Signature Padding, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+ LTC_PKCS #1 v2.00 Signature Encoding
+ @param msghash The hash to encode
+ @param msghashlen The length of the hash (octets)
+ @param saltlen The length of the salt desired (octets)
+ @param hash_algo The desired hash
+ @param modulus_bitlen The bit length of the RSA modulus
+ @param out [out] The destination of the encoding
+ @param outlen [in/out] The max size and resulting size of the encoded data
+ @return CRYPT_OK if successful
+*/
+int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
+ unsigned long saltlen, const struct algo_properties_st *hash_algo,
+ unsigned long modulus_bitlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned char *DB, *mask, *salt, *hash;
+ unsigned long x, y, hLen, modulus_len;
+ int err;
+
+ LTC_ARGCHK(msghash != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* ensure hash and PRNG are valid */
+ if ((err = hash_is_valid(hash_algo)) != CRYPT_OK) {
+ return err;
+ }
+
+ hLen = hash_algo->digest_size;
+ modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* check sizes */
+ if ((saltlen > modulus_len) || (modulus_len < hLen + saltlen + 2)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* allocate ram for DB/mask/salt/hash of size modulus_len */
+ DB = XMALLOC(modulus_len);
+ mask = XMALLOC(modulus_len);
+ salt = XMALLOC(modulus_len);
+ hash = XMALLOC(modulus_len);
+ if (DB == NULL || mask == NULL || salt == NULL || hash == NULL) {
+ if (DB != NULL) {
+ XFREE(DB);
+ }
+ if (mask != NULL) {
+ XFREE(mask);
+ }
+ if (salt != NULL) {
+ XFREE(salt);
+ }
+ if (hash != NULL) {
+ XFREE(hash);
+ }
+ return CRYPT_MEM;
+ }
+
+
+ /* generate random salt */
+ if (saltlen > 0) {
+ get_random_bytes(salt, saltlen);
+ }
+
+ zeromem(DB, 8);
+
+ /* M = (eight) 0x00 || msghash || salt, hash = H(M) */
+ err = hash_memory_multi(hash_algo, hash, &hLen, DB, (unsigned long)8, msghash, (unsigned long)msghashlen, salt, (unsigned long)saltlen, NULL, 0);
+ if (err != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* generate DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */
+ x = 0;
+ XMEMSET(DB + x, 0, modulus_len - saltlen - hLen - 2);
+ x += modulus_len - saltlen - hLen - 2;
+ DB[x++] = 0x01;
+ XMEMCPY(DB + x, salt, saltlen);
+ x += saltlen;
+
+ /* generate mask of length modulus_len - hLen - 1 from hash */
+ if ((err = pkcs_1_mgf1(hash_algo, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ /* xor against DB */
+ for (y = 0; y < (modulus_len - hLen - 1); y++) {
+ DB[y] ^= mask[y];
+ }
+
+ /* output is DB || hash || 0xBC */
+ if (*outlen < modulus_len) {
+ *outlen = modulus_len;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ /* DB len = modulus_len - hLen - 1 */
+ y = 0;
+ XMEMCPY(out + y, DB, modulus_len - hLen - 1);
+ y += modulus_len - hLen - 1;
+
+ /* hash */
+ XMEMCPY(out + y, hash, hLen);
+ y += hLen;
+
+ /* 0xBC */
+ out[y] = 0xBC;
+
+ /* now clear the 8*modulus_len - modulus_bitlen most significant bits */
+ out[0] &= 0xFF >> ((modulus_len<<3) - (modulus_bitlen-1));
+
+ /* store output size */
+ *outlen = modulus_len;
+ err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(DB, modulus_len);
+ zeromem(mask, modulus_len);
+ zeromem(salt, modulus_len);
+ zeromem(hash, modulus_len);
+#endif
+
+ XFREE(hash);
+ XFREE(salt);
+ XFREE(mask);
+ XFREE(DB);
+
+ return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_encode.c,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_decode.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_decode.c
new file mode 100644
index 00000000000..1bb08e31558
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_decode.c
@@ -0,0 +1,110 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/** @file pkcs_1_v1_5_decode.c
+ *
+ * LTC_PKCS #1 v1.5 Padding. (Andreas Lange)
+ */
+
+#ifdef LTC_PKCS_1
+
+/** @brief LTC_PKCS #1 v1.5 decode.
+ *
+ * @param msg The encoded data to decode
+ * @param msglen The length of the encoded data (octets)
+ * @param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ * @param modulus_bitlen The bit length of the RSA modulus
+ * @param out [out] Destination of decoding
+ * @param outlen [in/out] The max size and resulting size of the decoding
+ * @param is_valid [out] Boolean whether the padding was valid
+ *
+ * @return CRYPT_OK if successful (even if invalid)
+ */
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen,
+ int *is_valid)
+{
+ unsigned long modulus_len, ps_len, i;
+ int result;
+
+ /* default to invalid packet */
+ *is_valid = 0;
+
+ modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* test message size */
+
+ if ((msglen > modulus_len) || (modulus_len < 11)) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ /* separate encoded message */
+
+ if ((msg[0] != 0x00) || (msg[1] != (unsigned char)block_type)) {
+ result = CRYPT_INVALID_PACKET;
+ goto bail;
+ }
+
+ if (block_type == LTC_LTC_PKCS_1_EME) {
+ for (i = 2; i < modulus_len; i++) {
+ /* separator */
+ if (msg[i] == 0x00) { break; }
+ }
+ ps_len = i++ - 2;
+
+ if ((i >= modulus_len) || (ps_len < 8)) {
+ /* There was no octet with hexadecimal value 0x00 to separate ps from m,
+ * or the length of ps is less than 8 octets.
+ */
+ result = CRYPT_INVALID_PACKET;
+ goto bail;
+ }
+ } else {
+ for (i = 2; i < modulus_len - 1; i++) {
+ if (msg[i] != 0xFF) { break; }
+ }
+
+ /* separator check */
+ if (msg[i] != 0) {
+ /* There was no octet with hexadecimal value 0x00 to separate ps from m. */
+ result = CRYPT_INVALID_PACKET;
+ goto bail;
+ }
+
+ ps_len = i - 2;
+ }
+
+ if (*outlen < (msglen - (2 + ps_len + 1))) {
+ *outlen = msglen - (2 + ps_len + 1);
+ result = CRYPT_BUFFER_OVERFLOW;
+ goto bail;
+ }
+
+ *outlen = (msglen - (2 + ps_len + 1));
+ XMEMCPY(out, &msg[2 + ps_len + 1], *outlen);
+
+ /* valid packet */
+ *is_valid = 1;
+ result = CRYPT_OK;
+bail:
+ return result;
+} /* pkcs_1_v1_5_decode */
+
+#endif /* #ifdef LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_encode.c b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_encode.c
new file mode 100644
index 00000000000..048fe69280b
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/pkcs1/pkcs_1_v1_5_encode.c
@@ -0,0 +1,95 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/*! \file pkcs_1_v1_5_encode.c
+ *
+ * LTC_PKCS #1 v1.5 Padding (Andreas Lange)
+ */
+
+#ifdef LTC_PKCS_1
+
+/*! \brief LTC_PKCS #1 v1.5 encode.
+ *
+ * \param msg The data to encode
+ * \param msglen The length of the data to encode (octets)
+ * \param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ * \param modulus_bitlen The bit length of the RSA modulus
+ * \param out [out] The destination for the encoded data
+ * \param outlen [in/out] The max size and resulting size of the encoded data
+ *
+ * \return CRYPT_OK if successful
+ */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen)
+{
+ unsigned long modulus_len, ps_len, i;
+ unsigned char *ps;
+ int result;
+
+ /* valid block_type? */
+ if ((block_type != LTC_LTC_PKCS_1_EMSA) &&
+ (block_type != LTC_LTC_PKCS_1_EME)) {
+ return CRYPT_PK_INVALID_PADDING;
+ }
+
+ modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+ /* test message size */
+ if ((msglen + 11) > modulus_len) {
+ return CRYPT_PK_INVALID_SIZE;
+ }
+
+ if (*outlen < modulus_len) {
+ *outlen = modulus_len;
+ result = CRYPT_BUFFER_OVERFLOW;
+ goto bail;
+ }
+
+ /* generate an octets string PS */
+ ps = &out[2];
+ ps_len = modulus_len - msglen - 3;
+
+ if (block_type == LTC_LTC_PKCS_1_EME) {
+ /* now choose a random ps */
+ get_random_bytes(ps, ps_len);
+
+ /* transform zero bytes (if any) to non-zero random bytes */
+ for (i = 0; i < ps_len; i++) {
+ while (ps[i] == 0) {
+ get_random_bytes(&ps[i], 1);
+ }
+ }
+ } else {
+ XMEMSET(ps, 0xFF, ps_len);
+ }
+
+ /* create string of length modulus_len */
+ out[0] = 0x00;
+ out[1] = (unsigned char)block_type; /* block_type 1 or 2 */
+ out[2 + ps_len] = 0x00;
+ XMEMCPY(&out[2 + ps_len + 1], msg, msglen);
+ *outlen = modulus_len;
+
+ result = CRYPT_OK;
+bail:
+ return result;
+} /* pkcs_1_v1_5_encode */
+
+#endif /* #ifdef LTC_PKCS_1 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_decrypt_key.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_decrypt_key.c
new file mode 100644
index 00000000000..813a76544f1
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_decrypt_key.c
@@ -0,0 +1,107 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include "ncr-int.h"
+
+
+/**
+ @file rsa_decrypt_key.c
+ RSA LTC_PKCS #1 Decryption, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ LTC_PKCS #1 decrypt then v1.5 or OAEP depad
+ @param in The ciphertext
+ @param inlen The length of the ciphertext (octets)
+ @param out [out] The plaintext
+ @param outlen [in/out] The max size and resulting size of the plaintext (octets)
+ @param lparam The system "lparam" value
+ @param lparamlen The length of the lparam value (octets)
+ @param hash The desired hash
+ @param padding Type of padding (LTC_LTC_PKCS_1_OAEP or LTC_LTC_PKCS_1_V1_5)
+ @param stat [out] Result of the decryption, 1==valid, 0==invalid
+ @param key The corresponding private RSA key
+ @return CRYPT_OK if succcessul (even if invalid)
+*/
+int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ const struct algo_properties_st *hash, int padding,
+ int *stat, rsa_key *key)
+{
+ unsigned long modulus_bitlen, modulus_bytelen, x;
+ int err;
+ unsigned char *tmp;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(stat != NULL);
+
+ /* default to invalid */
+ *stat = 0;
+
+ /* valid padding? */
+
+ if ((padding != LTC_LTC_PKCS_1_V1_5) &&
+ (padding != LTC_LTC_PKCS_1_OAEP)) {
+ return CRYPT_PK_INVALID_PADDING;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_OAEP) {
+ /* valid hash ? */
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* get modulus len in bits */
+ modulus_bitlen = mp_count_bits( (&key->N));
+
+ /* outlen must be at least the size of the modulus */
+ modulus_bytelen = mp_unsigned_bin_size( (&key->N));
+ if (modulus_bytelen != inlen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* allocate ram */
+ tmp = XMALLOC(inlen);
+ if (tmp == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* rsa decode the packet */
+ x = inlen;
+ if ((err = rsa_exptmod(in, inlen, tmp, &x, PK_PRIVATE, key)) != CRYPT_OK) {
+ XFREE(tmp);
+ return err;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_OAEP) {
+ /* now OAEP decode the packet */
+ err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, hash,
+ out, outlen, stat);
+ } else {
+ /* now LTC_PKCS #1 v1.5 depad the packet */
+ err = pkcs_1_v1_5_decode(tmp, x, LTC_LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat);
+ }
+
+ XFREE(tmp);
+ return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_decrypt_key.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_encrypt_key.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_encrypt_key.c
new file mode 100644
index 00000000000..8d3f2db1daa
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_encrypt_key.c
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include "ncr-int.h"
+
+/**
+ @file rsa_encrypt_key.c
+ RSA LTC_PKCS #1 encryption, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ (LTC_PKCS #1 v2.0) OAEP pad then encrypt
+ @param in The plaintext
+ @param inlen The length of the plaintext (octets)
+ @param out [out] The ciphertext
+ @param outlen [in/out] The max size and resulting size of the ciphertext
+ @param lparam The system "lparam" for the encryption
+ @param lparamlen The length of lparam (octets)
+ @param hash The desired hash
+ @param padding Type of padding (LTC_LTC_PKCS_1_OAEP or LTC_LTC_PKCS_1_V1_5)
+ @param key The RSA key to encrypt to
+ @return CRYPT_OK if successful
+*/
+int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ const struct algo_properties_st *hash, int padding, rsa_key *key)
+{
+ unsigned long modulus_bitlen, modulus_bytelen, x;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* valid padding? */
+ if ((padding != LTC_LTC_PKCS_1_V1_5) &&
+ (padding != LTC_LTC_PKCS_1_OAEP)) {
+ return CRYPT_PK_INVALID_PADDING;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_OAEP) {
+ /* valid hash? */
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* get modulus len in bits */
+ modulus_bitlen = mp_count_bits( (&key->N));
+
+ /* outlen must be at least the size of the modulus */
+ modulus_bytelen = mp_unsigned_bin_size( (&key->N));
+ if (modulus_bytelen > *outlen) {
+ *outlen = modulus_bytelen;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_OAEP) {
+ /* OAEP pad the key */
+ x = *outlen;
+ if ((err = pkcs_1_oaep_encode(in, inlen, lparam,
+ lparamlen, modulus_bitlen, hash,
+ out, &x)) != CRYPT_OK) {
+ return err;
+ }
+ } else {
+ /* LTC_PKCS #1 v1.5 pad the key */
+ x = *outlen;
+ if ((err = pkcs_1_v1_5_encode(in, inlen, LTC_LTC_PKCS_1_EME,
+ modulus_bitlen,
+ out, &x)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* rsa exptmod the OAEP or LTC_PKCS #1 v1.5 pad */
+ return rsa_exptmod(out, x, out, outlen, PK_PUBLIC, key);
+}
+
+#endif /* LTC_MRSA */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_encrypt_key.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_export.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_export.c
new file mode 100644
index 00000000000..21f859caaab
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_export.c
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include <ncr-int.h>
+
+/**
+ @file rsa_export.c
+ Export RSA LTC_PKCS keys, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ This will export either an RSAPublicKey or RSAPrivateKey [defined in LTC_PKCS #1 v2.1]
+ @param out [out] Destination of the packet
+ @param outlen [in/out] The max size and resulting size of the packet
+ @param type The type of exported key (PK_PRIVATE or PK_PUBLIC)
+ @param key The RSA key to export
+ @return CRYPT_OK if successful
+*/
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key)
+{
+ unsigned long zero=0;
+ int err;
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* type valid? */
+ if (!(key->type == PK_PRIVATE) && (type == PK_PRIVATE)) {
+ return CRYPT_PK_INVALID_TYPE;
+ }
+
+ if (type == PK_PRIVATE) {
+ /* private key */
+ /* output is
+ Version, n, e, d, p, q, d mod (p-1), d mod (q - 1), 1/q mod p
+ */
+ return der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+ LTC_ASN1_INTEGER, 1UL, &key->N,
+ LTC_ASN1_INTEGER, 1UL, &key->e,
+ LTC_ASN1_INTEGER, 1UL, &key->d,
+ LTC_ASN1_INTEGER, 1UL, &key->p,
+ LTC_ASN1_INTEGER, 1UL, &key->q,
+ LTC_ASN1_INTEGER, 1UL, &key->dP,
+ LTC_ASN1_INTEGER, 1UL, &key->dQ,
+ LTC_ASN1_INTEGER, 1UL, &key->qP,
+ LTC_ASN1_EOL, 0UL, NULL);
+ } else {
+ unsigned long tmplen = (mp_count_bits(&key->N)/8)*2+8;
+ unsigned char* tmp = XMALLOC(tmplen);
+
+ if (tmp == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = der_encode_sequence_multi(tmp, &tmplen,
+ LTC_ASN1_INTEGER, 1UL, &key->N,
+ LTC_ASN1_INTEGER, 1UL, &key->e,
+ LTC_ASN1_EOL, 0UL, NULL);
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+
+ err = der_encode_subject_public_key_info(out, outlen,
+ PKA_RSA, tmp, tmplen, LTC_ASN1_NULL, NULL, 0);
+
+error:
+ XFREE(tmp);
+ return err;
+ }
+}
+
+#endif /* LTC_MRSA */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_export.c,v $ */
+/* $Revision: 1.17 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_exptmod.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_exptmod.c
new file mode 100644
index 00000000000..35ebfe3bb96
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_exptmod.c
@@ -0,0 +1,147 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ *
+ * Added RSA blinding --nmav
+ */
+#include "tomcrypt.h"
+
+/**
+ @file rsa_exptmod.c
+ RSA LTC_PKCS exptmod, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Compute an RSA modular exponentiation
+ @param in The input data to send into RSA
+ @param inlen The length of the input (octets)
+ @param out [out] The destination
+ @param outlen [in/out] The max size and resulting size of the output
+ @param which Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC
+ @param key The RSA key to use
+ @return CRYPT_OK if successful
+*/
+int rsa_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key)
+{
+ mp_int tmp, tmpa, tmpb, rnd, rndi /* inverse of rnd */;
+ unsigned long x;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* is the key of the right type for the operation? */
+ if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) {
+ return CRYPT_PK_NOT_PRIVATE;
+ }
+
+ /* must be a private or public operation */
+ if (which != PK_PRIVATE && which != PK_PUBLIC) {
+ return CRYPT_PK_INVALID_TYPE;
+ }
+
+ /* init and copy into tmp */
+ if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, &rnd, &rndi, NULL)) != CRYPT_OK)
+ { return err; }
+ if ((err = mp_read_unsigned_bin(&tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK)
+ { goto error; }
+
+ /* sanity check on the input */
+ if (mp_cmp(&key->N, &tmp) == LTC_MP_LT) {
+ err = CRYPT_PK_INVALID_SIZE;
+ goto error;
+ }
+
+ /* are we using the private exponent and is the key optimized? */
+ if (which == PK_PRIVATE) {
+ /* do blinding */
+ err = mp_rand(&rnd, mp_count_bits(&key->N));
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+
+ /* rndi = 1/rnd mod N */
+ err = mp_invmod( &rnd, &key->N, &rndi);
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+
+ /* rnd = rnd^e */
+ err = mp_exptmod( &rnd, &key->e, &key->N, &rnd);
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+
+ /* tmp = tmp*rnd mod N */
+ err = mp_mulmod( &tmp, &rnd, &key->N, &tmp);
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+
+ /* tmpa = tmp^dP mod p */
+ if ((err = mp_exptmod(&tmp, &key->dP, &key->p, &tmpa)) != CRYPT_OK) { goto error; }
+
+ /* tmpb = tmp^dQ mod q */
+ if ((err = mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb)) != CRYPT_OK) { goto error; }
+
+ /* tmp = (tmpa - tmpb) * qInv (mod p) */
+ if ((err = mp_sub(&tmpa, &tmpb, &tmp)) != CRYPT_OK) { goto error; }
+ if ((err = mp_mulmod(&tmp, &key->qP, &key->p, &tmp)) != CRYPT_OK) { goto error; }
+
+ /* tmp = tmpb + q * tmp */
+ if ((err = mp_mul(&tmp, &key->q, &tmp)) != CRYPT_OK) { goto error; }
+ if ((err = mp_add(&tmp, &tmpb, &tmp)) != CRYPT_OK) { goto error; }
+
+ /* unblind */
+ err = mp_mulmod( &tmp, &rndi, &key->N, &tmp);
+ if (err != CRYPT_OK) {
+ goto error;
+ }
+ } else {
+ /* exptmod it */
+ if ((err = mp_exptmod(&tmp, &key->e, &key->N, &tmp)) != CRYPT_OK) { goto error; }
+ }
+
+ /* read it back */
+ x = (unsigned long)mp_unsigned_bin_size(&key->N);
+ if (x > *outlen) {
+ *outlen = x;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto error;
+ }
+
+ /* this should never happen ... */
+ if (mp_unsigned_bin_size(&tmp) > mp_unsigned_bin_size(&key->N)) {
+ err = CRYPT_ERROR;
+ goto error;
+ }
+ *outlen = x;
+
+ /* convert it */
+ zeromem(out, x);
+ if ((err = mp_to_unsigned_bin(&tmp, out+(x-mp_unsigned_bin_size(&tmp)))) != CRYPT_OK) { goto error; }
+
+ /* clean up and return */
+ err = CRYPT_OK;
+error:
+ mp_clear_multi(&tmp, &tmpa, &tmpb, &rnd, &rndi, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_exptmod.c,v $ */
+/* $Revision: 1.18 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_free.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_free.c
new file mode 100644
index 00000000000..d38b266197f
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_free.c
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file rsa_free.c
+ Free an RSA key, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Free an RSA key from memory
+ @param key The RSA key to free
+*/
+void rsa_free(rsa_key *key)
+{
+ LTC_ARGCHKVD(key != NULL);
+ mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL);
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_free.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_import.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_import.c
new file mode 100644
index 00000000000..87cb1030d47
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_import.c
@@ -0,0 +1,128 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file rsa_import.c
+ Import a LTC_PKCS RSA key, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Import an RSAPublicKey or RSAPrivateKey [two-prime only, only support >= 1024-bit keys, defined in LTC_PKCS #1 v2.1]
+ @param in The packet to import from
+ @param inlen It's length (octets)
+ @param key [out] Destination for newly imported key
+ @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key)
+{
+ int err;
+ mp_int zero;
+ unsigned char *tmpbuf=NULL;
+ unsigned long tmpbuf_len;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* init key */
+ if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
+ &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* see if the OpenSSL DER format RSA public key will work */
+ tmpbuf_len = MAX_RSA_SIZE * 8;
+ tmpbuf = XCALLOC(1, tmpbuf_len);
+ if (tmpbuf == NULL) {
+ err = CRYPT_MEM;
+ goto LBL_ERR;
+ }
+
+ err = der_decode_subject_public_key_info(in, inlen,
+ PKA_RSA, tmpbuf, &tmpbuf_len,
+ LTC_ASN1_NULL, NULL, 0);
+
+ if (err == CRYPT_OK) { /* SubjectPublicKeyInfo format */
+
+ /* now it should be SEQUENCE { INTEGER, INTEGER } */
+ if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len,
+ LTC_ASN1_INTEGER, 1UL, &key->N,
+ LTC_ASN1_INTEGER, 1UL, &key->e,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ XFREE(tmpbuf);
+
+ key->type = PK_PUBLIC;
+ return CRYPT_OK;
+ }
+
+ XFREE(tmpbuf);
+
+ /* not SSL public key, try to match against LTC_PKCS #1 standards */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_INTEGER, 1UL, &key->N,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp_d(&key->N, 0) == LTC_MP_EQ) {
+ if ((err = mp_init(&zero)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ /* it's a private key */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_INTEGER, 1UL, &zero,
+ LTC_ASN1_INTEGER, 1UL, &key->N,
+ LTC_ASN1_INTEGER, 1UL, &key->e,
+ LTC_ASN1_INTEGER, 1UL, &key->d,
+ LTC_ASN1_INTEGER, 1UL, &key->p,
+ LTC_ASN1_INTEGER, 1UL, &key->q,
+ LTC_ASN1_INTEGER, 1UL, &key->dP,
+ LTC_ASN1_INTEGER, 1UL, &key->dQ,
+ LTC_ASN1_INTEGER, 1UL, &key->qP,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ mp_clear(&zero);
+ goto LBL_ERR;
+ }
+ mp_clear(&zero);
+ key->type = PK_PRIVATE;
+ } else if (mp_cmp_d(&key->N, 1) == LTC_MP_EQ) {
+ /* we don't support multi-prime RSA */
+ err = CRYPT_PK_INVALID_TYPE;
+ goto LBL_ERR;
+ } else {
+ /* it's a public key and we lack e */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_INTEGER, 1UL, &key->N,
+ LTC_ASN1_INTEGER, 1UL, &key->e,
+ LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ key->type = PK_PUBLIC;
+ }
+ return CRYPT_OK;
+LBL_ERR:
+ XFREE(tmpbuf);
+ mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL);
+ return err;
+}
+
+#endif /* LTC_MRSA */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_import.c,v $ */
+/* $Revision: 1.23 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_make_key.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_make_key.c
new file mode 100644
index 00000000000..6718f09bc9f
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_make_key.c
@@ -0,0 +1,105 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+
+/**
+ @file rsa_make_key.c
+ RSA key generation, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ Create an RSA key
+ @param size The size of the modulus (key size) desired (octets)
+ @param e The "e" value (public key). e==65537 is a good choice
+ @param key [out] Destination of a newly created private key pair
+ @return CRYPT_OK if successful, upon error all allocated ram is freed
+*/
+int rsa_make_key(int size, long e, rsa_key *key)
+{
+ mp_int p, q, tmp1, tmp2, tmp3;
+ int err;
+
+ LTC_ARGCHK(key != NULL);
+
+ if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) {
+ return CRYPT_INVALID_KEYSIZE;
+ }
+
+ if ((e < 3) || ((e & 1) == 0)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* make primes p and q (optimization provided by Wayne Scott) */
+ if ((err = mp_set_int(&tmp3, e)) != CRYPT_OK) { goto cleanup; } /* tmp3 = e */
+
+ /* make prime "p" */
+ do {
+ if ((err = rand_prime( &p, size/2)) != CRYPT_OK) { goto cleanup; }
+ if ((err = mp_sub_d( &p, 1, &tmp1)) != CRYPT_OK) { goto cleanup; } /* tmp1 = p-1 */
+ if ((err = mp_gcd( &tmp1, &tmp3, &tmp2)) != CRYPT_OK) { goto cleanup; } /* tmp2 = gcd(p-1, e) */
+ } while (mp_cmp_d( &tmp2, 1) != 0); /* while e divides p-1 */
+
+ /* make prime "q" */
+ do {
+ if ((err = rand_prime( &q, size/2)) != CRYPT_OK) { goto cleanup; }
+ if ((err = mp_sub_d( &q, 1, &tmp1)) != CRYPT_OK) { goto cleanup; } /* tmp1 = q-1 */
+ if ((err = mp_gcd( &tmp1, &tmp3, &tmp2)) != CRYPT_OK) { goto cleanup; } /* tmp2 = gcd(q-1, e) */
+ } while (mp_cmp_d( &tmp2, 1) != 0); /* while e divides q-1 */
+
+ /* tmp1 = lcm(p-1, q-1) */
+ if ((err = mp_sub_d( &p, 1, &tmp2)) != CRYPT_OK) { goto cleanup; } /* tmp2 = p-1 */
+ /* tmp1 = q-1 (previous do/while loop) */
+ if ((err = mp_lcm( &tmp1, &tmp2, &tmp1)) != CRYPT_OK) { goto cleanup; } /* tmp1 = lcm(p-1, q-1) */
+
+ /* make key */
+ if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+ goto cleanup;
+ }
+
+ if ((err = mp_set_int( &key->e, e)) != CRYPT_OK) { goto errkey; } /* key->e = e */
+ if ((err = mp_invmod( &key->e, &tmp1, &key->d)) != CRYPT_OK) { goto errkey; } /* key->d = 1/e mod lcm(p-1,q-1) */
+ if ((err = mp_mul( &p, &q, &key->N)) != CRYPT_OK) { goto errkey; } /* key->N = pq */
+
+ /* optimize for CRT now */
+ /* find d mod q-1 and d mod p-1 */
+ if ((err = mp_sub_d( &p, 1, &tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = q-1 */
+ if ((err = mp_sub_d( &q, 1, &tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = p-1 */
+ if ((err = mp_mod( &key->d, &tmp1, &key->dP)) != CRYPT_OK) { goto errkey; } /* dP = d mod p-1 */
+ if ((err = mp_mod( &key->d, &tmp2, &key->dQ)) != CRYPT_OK) { goto errkey; } /* dQ = d mod q-1 */
+ if ((err = mp_invmod( &q, &p, &key->qP)) != CRYPT_OK) { goto errkey; } /* qP = 1/q mod p */
+
+ if ((err = mp_copy( &p, &key->p)) != CRYPT_OK) { goto errkey; }
+ if ((err = mp_copy( &q, &key->q)) != CRYPT_OK) { goto errkey; }
+
+ /* set key type (in this case it's CRT optimized) */
+ key->type = PK_PRIVATE;
+
+ /* return ok and free temps */
+ err = CRYPT_OK;
+ goto cleanup;
+errkey:
+ mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL);
+cleanup:
+ mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_make_key.c,v $ */
+/* $Revision: 1.16 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_sign_hash.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_sign_hash.c
new file mode 100644
index 00000000000..faf13d27b8f
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_sign_hash.c
@@ -0,0 +1,130 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include "ncr-int.h"
+
+
+/**
+ @file rsa_sign_hash.c
+ RSA LTC_PKCS #1 v1.5 and v2 PSS sign hash, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ LTC_PKCS #1 pad then sign
+ @param in The hash to sign
+ @param inlen The length of the hash to sign (octets)
+ @param out [out] The signature
+ @param outlen [in/out] The max size and resulting size of the signature
+ @param padding Type of padding (LTC_LTC_PKCS_1_PSS or LTC_LTC_PKCS_1_V1_5)
+ @param hash The desired hash
+ @param saltlen The length of the salt desired (octets)
+ @param key The private RSA key to use
+ @return CRYPT_OK if successful
+*/
+int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ int padding,
+ const struct algo_properties_st *hash, unsigned long saltlen,
+ rsa_key *key)
+{
+ unsigned long modulus_bitlen, modulus_bytelen, x, y;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* valid padding? */
+ if ((padding != LTC_LTC_PKCS_1_V1_5) && (padding != LTC_LTC_PKCS_1_PSS)) {
+ return CRYPT_PK_INVALID_PADDING;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_PSS) {
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* get modulus len in bits */
+ modulus_bitlen = mp_count_bits((&key->N));
+
+ /* outlen must be at least the size of the modulus */
+ modulus_bytelen = mp_unsigned_bin_size((&key->N));
+ if (modulus_bytelen > *outlen) {
+ *outlen = modulus_bytelen;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_PSS) {
+ /* PSS pad the key */
+ x = *outlen;
+ if ((err = pkcs_1_pss_encode(in, inlen, saltlen,
+ hash, modulus_bitlen, out, &x)) != CRYPT_OK) {
+ return err;
+ }
+ } else {
+ /* LTC_PKCS #1 v1.5 pad the hash */
+ unsigned char *tmpin;
+ ltc_asn1_list digestinfo[2], siginfo[2];
+ oid_st st;
+
+ /* not all hashes have OIDs... so sad */
+ if (hash_get_oid(hash, &st) != CRYPT_OK) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* construct the SEQUENCE
+ SEQUENCE {
+ SEQUENCE {hashoid OID
+ blah NULL
+ }
+ hash OCTET STRING
+ }
+ */
+ LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, st.OID, st.OIDlen);
+ LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
+ LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, in, inlen);
+
+ /* allocate memory for the encoding */
+ y = mp_unsigned_bin_size(&key->N);
+ tmpin = XMALLOC(y);
+ if (tmpin == NULL) {
+ return CRYPT_MEM;
+ }
+
+ if ((err = der_encode_sequence(siginfo, 2, tmpin, &y)) != CRYPT_OK) {
+ XFREE(tmpin);
+ return err;
+ }
+
+ x = *outlen;
+ if ((err = pkcs_1_v1_5_encode(tmpin, y, LTC_LTC_PKCS_1_EMSA,
+ modulus_bitlen,
+ out, &x)) != CRYPT_OK) {
+ XFREE(tmpin);
+ return err;
+ }
+ XFREE(tmpin);
+ }
+
+ /* RSA encode it */
+ return rsa_exptmod(out, x, out, outlen, PK_PRIVATE, key);
+}
+
+#endif /* LTC_MRSA */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_sign_hash.c,v $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtomcrypt/pk/rsa/rsa_verify_hash.c b/crypto/userspace/libtomcrypt/pk/rsa/rsa_verify_hash.c
new file mode 100644
index 00000000000..803b7cd4edf
--- /dev/null
+++ b/crypto/userspace/libtomcrypt/pk/rsa/rsa_verify_hash.c
@@ -0,0 +1,170 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include "tomcrypt.h"
+#include "ncr-int.h"
+
+
+/**
+ @file rsa_verify_hash.c
+ RSA LTC_PKCS #1 v1.5 or v2 PSS signature verification, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+ LTC_PKCS #1 de-sign then v1.5 or PSS depad
+ @param sig The signature data
+ @param siglen The length of the signature data (octets)
+ @param hash The hash of the message that was signed
+ @param hashlen The length of the hash of the message that was signed (octets)
+ @param padding Type of padding (LTC_LTC_PKCS_1_PSS or LTC_LTC_PKCS_1_V1_5)
+ @param hash_algo The desired hash
+ @param saltlen The length of the salt used during signature
+ @param stat [out] The result of the signature comparison, 1==valid, 0==invalid
+ @param key The public RSA key corresponding to the key that performed the signature
+ @return CRYPT_OK on success (even if the signature is invalid)
+*/
+int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int padding,
+ const struct algo_properties_st *hash_algo, unsigned long saltlen,
+ int *stat, rsa_key *key)
+{
+ unsigned long modulus_bitlen, modulus_bytelen, x;
+ int err;
+ unsigned char *tmpbuf;
+
+ LTC_ARGCHK(hash != NULL);
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* default to invalid */
+ *stat = 0;
+
+ /* valid padding? */
+
+ if ((padding != LTC_LTC_PKCS_1_V1_5) &&
+ (padding != LTC_LTC_PKCS_1_PSS)) {
+ return CRYPT_PK_INVALID_PADDING;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_PSS) {
+ /* valid hash ? */
+ if ((err = hash_is_valid(hash_algo)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
+ /* get modulus len in bits */
+ modulus_bitlen = mp_count_bits( (&key->N));
+
+ /* outlen must be at least the size of the modulus */
+ modulus_bytelen = mp_unsigned_bin_size( (&key->N));
+ if (modulus_bytelen != siglen) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* allocate temp buffer for decoded sig */
+ tmpbuf = XMALLOC(siglen);
+ if (tmpbuf == NULL) {
+ return CRYPT_MEM;
+ }
+
+ /* RSA decode it */
+ x = siglen;
+ if ((err = rsa_exptmod(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+ XFREE(tmpbuf);
+ return err;
+ }
+
+ /* make sure the output is the right size */
+ if (x != siglen) {
+ XFREE(tmpbuf);
+ return CRYPT_INVALID_PACKET;
+ }
+
+ if (padding == LTC_LTC_PKCS_1_PSS) {
+ /* PSS decode and verify it */
+ err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_algo, modulus_bitlen, stat);
+ } else {
+ /* LTC_PKCS #1 v1.5 decode it */
+ unsigned char *out;
+ unsigned long outlen, loid[16];
+ int decoded;
+ ltc_asn1_list digestinfo[2], siginfo[2];
+ oid_st st;
+
+ /* not all hashes have OIDs... so sad */
+ if (hash_get_oid(hash_algo, &st) != CRYPT_OK) {
+ err = CRYPT_INVALID_ARG;
+ goto bail_2;
+ }
+
+ /* allocate temp buffer for decoded hash */
+ outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
+ out = XMALLOC(outlen);
+ if (out == NULL) {
+ err = CRYPT_MEM;
+ goto bail_2;
+ }
+
+ if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
+ XFREE(out);
+ goto bail_2;
+ }
+
+ /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
+ /* construct the SEQUENCE
+ SEQUENCE {
+ SEQUENCE {hashoid OID
+ blah NULL
+ }
+ hash OCTET STRING
+ }
+ */
+ LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
+ LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
+ LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen);
+
+ if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+ XFREE(out);
+ goto bail_2;
+ }
+
+ /* test OID */
+ if ((digestinfo[0].size == st.OIDlen) &&
+ (XMEMCMP(digestinfo[0].data, st.OID, sizeof(unsigned long) * st.OIDlen) == 0) &&
+ (siginfo[1].size == hashlen) &&
+ (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
+ *stat = 1;
+ }
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(out, outlen);
+#endif
+ XFREE(out);
+ }
+
+bail_2:
+#ifdef LTC_CLEAN_STACK
+ zeromem(tmpbuf, siglen);
+#endif
+ XFREE(tmpbuf);
+ return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_verify_hash.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/crypto/userspace/libtommath/LICENSE b/crypto/userspace/libtommath/LICENSE
new file mode 100644
index 00000000000..5baa792a650
--- /dev/null
+++ b/crypto/userspace/libtommath/LICENSE
@@ -0,0 +1,4 @@
+LibTomMath is hereby released into the Public Domain.
+
+-- Tom St Denis
+
diff --git a/crypto/userspace/libtommath/bn_error.c b/crypto/userspace/libtommath/bn_error.c
new file mode 100644
index 00000000000..b1b7177e61f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_error.c
@@ -0,0 +1,47 @@
+#include <tommath.h>
+#ifdef BN_ERROR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+static const struct {
+ int code;
+ char *msg;
+} msgs[] = {
+ { MP_OKAY, "Successful" },
+ { MP_MEM, "Out of heap" },
+ { MP_VAL, "Value out of range" }
+};
+
+/* return a char * string for a given code */
+char *mp_error_to_string(int code)
+{
+ int x;
+
+ /* scan the lookup table for the given message */
+ for (x = 0; x < (int)(sizeof(msgs) / sizeof(msgs[0])); x++) {
+ if (msgs[x].code == code) {
+ return msgs[x].msg;
+ }
+ }
+
+ /* generic reply for invalid code */
+ return "Invalid error code";
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_error.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_fast_mp_invmod.c b/crypto/userspace/libtommath/bn_fast_mp_invmod.c
new file mode 100644
index 00000000000..ff03dfffe3d
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_fast_mp_invmod.c
@@ -0,0 +1,148 @@
+#include <tommath.h>
+#ifdef BN_FAST_MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes the modular inverse via binary extended euclidean algorithm,
+ * that is c = 1/a mod b
+ *
+ * Based on slow invmod except this is optimized for the case where b is
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, B, D;
+ int res, neg;
+
+ /* 2. [modified] b must be odd */
+ if (mp_iseven (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* init all our temps */
+ if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* x == modulus, y == value to invert */
+ if ((res = mp_copy (b, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* we need y = |a| */
+ if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set (&D, 1);
+
+top:
+ /* 4. while u is even do */
+ while (mp_iseven (&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if B is odd then */
+ if (mp_isodd (&B) == 1) {
+ if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* B = B/2 */
+ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven (&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if D is odd then */
+ if (mp_isodd (&D) == 1) {
+ /* D = (D-x)/2 */
+ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* D = D/2 */
+ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp (&u, &v) != MP_LT) {
+ /* u = u - v, B = B - D */
+ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, D = D - B */
+ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* if not zero goto step 4 */
+ if (mp_iszero (&u) == 0) {
+ goto top;
+ }
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d (&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* b is now the inverse */
+ neg = a->sign;
+ while (D.sign == MP_NEG) {
+ if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ mp_exch (&D, c);
+ c->sign = neg;
+ res = MP_OKAY;
+
+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_mp_invmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_fast_mp_montgomery_reduce.c b/crypto/userspace/libtommath/bn_fast_mp_montgomery_reduce.c
new file mode 100644
index 00000000000..b6c0694bd2f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_fast_mp_montgomery_reduce.c
@@ -0,0 +1,172 @@
+#include <tommath.h>
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int ix, res, olduse;
+ mp_word W[MP_WARRAY];
+
+ /* get old used count */
+ olduse = x->used;
+
+ /* grow a as required */
+ if (x->alloc < n->used + 1) {
+ if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* first we have to get the digits of the input into
+ * an array of double precision words W[...]
+ */
+ {
+ register mp_word *_W;
+ register mp_digit *tmpx;
+
+ /* alias for the W[] array */
+ _W = W;
+
+ /* alias for the digits of x*/
+ tmpx = x->dp;
+
+ /* copy the digits of a into W[0..a->used-1] */
+ for (ix = 0; ix < x->used; ix++) {
+ *_W++ = *tmpx++;
+ }
+
+ /* zero the high words of W[a->used..m->used*2] */
+ for (; ix < n->used * 2 + 1; ix++) {
+ *_W++ = 0;
+ }
+ }
+
+ /* now we proceed to zero successive digits
+ * from the least significant upwards
+ */
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * m' mod b
+ *
+ * We avoid a double precision multiplication (which isn't required)
+ * by casting the value down to a mp_digit. Note this requires
+ * that W[ix-1] have the carry cleared (see after the inner loop)
+ */
+ register mp_digit mu;
+ mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i
+ *
+ * This is computed in place and on the fly. The multiplication
+ * by b**i is handled by offseting which columns the results
+ * are added to.
+ *
+ * Note the comba method normally doesn't handle carries in the
+ * inner loop In this case we fix the carry from the previous
+ * column since the Montgomery reduction requires digits of the
+ * result (so far) [see above] to work. This is
+ * handled by fixing up one carry after the inner loop. The
+ * carry fixups are done in order so after these loops the
+ * first m->used words of W[] have the carries fixed
+ */
+ {
+ register int iy;
+ register mp_digit *tmpn;
+ register mp_word *_W;
+
+ /* alias for the digits of the modulus */
+ tmpn = n->dp;
+
+ /* Alias for the columns set by an offset of ix */
+ _W = W + ix;
+
+ /* inner loop */
+ for (iy = 0; iy < n->used; iy++) {
+ *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+ }
+ }
+
+ /* now fix carry for next digit, W[ix+1] */
+ W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+ }
+
+ /* now we have to propagate the carries and
+ * shift the words downward [all those least
+ * significant digits we zeroed].
+ */
+ {
+ register mp_digit *tmpx;
+ register mp_word *_W, *_W1;
+
+ /* nox fix rest of carries */
+
+ /* alias for current word */
+ _W1 = W + ix;
+
+ /* alias for next word, where the carry goes */
+ _W = W + ++ix;
+
+ for (; ix <= n->used * 2 + 1; ix++) {
+ *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+ }
+
+ /* copy out, A = A/b**n
+ *
+ * The result is A/b**n but instead of converting from an
+ * array of mp_word to mp_digit than calling mp_rshd
+ * we just copy them in the right order
+ */
+
+ /* alias for destination word */
+ tmpx = x->dp;
+
+ /* alias for shifted double precision result */
+ _W = W + n->used;
+
+ for (ix = 0; ix < n->used + 1; ix++) {
+ *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+ }
+
+ /* zero oldused digits, if the input a was larger than
+ * m->used+1 we'll have to clear the digits
+ */
+ for (; ix < olduse; ix++) {
+ *tmpx++ = 0;
+ }
+ }
+
+ /* set the max used and clamp */
+ x->used = n->used + 1;
+ mp_clamp (x);
+
+ /* if A >= m then A = A - m */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ return s_mp_sub (x, n, x);
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_mp_montgomery_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_fast_s_mp_mul_digs.c b/crypto/userspace/libtommath/bn_fast_s_mp_mul_digs.c
new file mode 100644
index 00000000000..91e10d670fe
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_fast_s_mp_mul_digs.c
@@ -0,0 +1,107 @@
+#include <tommath.h>
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY];
+ register mp_word _W;
+
+ /* grow the destination as required */
+ if (c->alloc < digs) {
+ if ((res = mp_grow (c, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = MIN(digs, a->used + b->used);
+
+ /* clear the carry */
+ _W = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty;
+ int iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; ++iz) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+
+ }
+
+ /* store term */
+ W[ix] = ((mp_digit)_W) & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ register mp_digit *tmpc;
+ tmpc = c->dp;
+ for (ix = 0; ix < pa+1; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpc++ = 0;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_digs.c,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_fast_s_mp_mul_high_digs.c b/crypto/userspace/libtommath/bn_fast_s_mp_mul_high_digs.c
new file mode 100644
index 00000000000..5b114d717ab
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_fast_s_mp_mul_high_digs.c
@@ -0,0 +1,98 @@
+#include <tommath.h>
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* this is a modified version of fast_s_mul_digs that only produces
+ * output digits *above* digs. See the comments for fast_s_mul_digs
+ * to see how it works.
+ *
+ * This is used in the Barrett reduction since for one of the multiplications
+ * only the higher digits were needed. This essentially halves the work.
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ */
+int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ /* grow the destination as required */
+ pa = a->used + b->used;
+ if (c->alloc < pa) {
+ if ((res = mp_grow (c, pa)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = a->used + b->used;
+ _W = 0;
+ for (ix = digs; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially its
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+ /* store term */
+ W[ix] = ((mp_digit)_W) & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ register mp_digit *tmpc;
+
+ tmpc = c->dp + digs;
+ for (ix = digs; ix < pa; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpc++ = 0;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_high_digs.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_fast_s_mp_sqr.c b/crypto/userspace/libtommath/bn_fast_s_mp_sqr.c
new file mode 100644
index 00000000000..19e92ef1807
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_fast_s_mp_sqr.c
@@ -0,0 +1,114 @@
+#include <tommath.h>
+#ifdef BN_FAST_S_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens. You double all those
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY], *tmpx;
+ mp_word W1;
+
+ /* grow the destination as required */
+ pa = a->used + a->used;
+ if (b->alloc < pa) {
+ if ((res = mp_grow (b, pa)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ W1 = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_word _W;
+ mp_digit *tmpy;
+
+ /* clear counter */
+ _W = 0;
+
+ /* get offsets into the two bignums */
+ ty = MIN(a->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = a->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* now for squaring tx can never equal ty
+ * we halve the distance since they approach at a rate of 2x
+ * and we have to round because odd cases need to be executed
+ */
+ iy = MIN(iy, (ty-tx+1)>>1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+ /* double the inner product and add carry */
+ _W = _W + _W + W1;
+
+ /* even columns have the square term in them */
+ if ((ix&1) == 0) {
+ _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+ }
+
+ /* store it */
+ W[ix] = (mp_digit)(_W & MP_MASK);
+
+ /* make next carry */
+ W1 = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = b->used;
+ b->used = a->used+a->used;
+
+ {
+ mp_digit *tmpb;
+ tmpb = b->dp;
+ for (ix = 0; ix < pa; ix++) {
+ *tmpb++ = W[ix] & MP_MASK;
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpb++ = 0;
+ }
+ }
+ mp_clamp (b);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_2expt.c b/crypto/userspace/libtommath/bn_mp_2expt.c
new file mode 100644
index 00000000000..f422ffc9946
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_2expt.c
@@ -0,0 +1,48 @@
+#include <tommath.h>
+#ifdef BN_MP_2EXPT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes a = 2**b
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+int
+mp_2expt (mp_int * a, int b)
+{
+ int res;
+
+ /* zero a as per default */
+ mp_zero (a);
+
+ /* grow a to accomodate the single bit */
+ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* set the used count of where the bit will go */
+ a->used = b / DIGIT_BIT + 1;
+
+ /* put the single bit in its place */
+ a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_2expt.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_abs.c b/crypto/userspace/libtommath/bn_mp_abs.c
new file mode 100644
index 00000000000..09dd7229eb5
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_abs.c
@@ -0,0 +1,43 @@
+#include <tommath.h>
+#ifdef BN_MP_ABS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = |a|
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+int
+mp_abs (mp_int * a, mp_int * b)
+{
+ int res;
+
+ /* copy a to b */
+ if (a != b) {
+ if ((res = mp_copy (a, b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* force the sign of b to positive */
+ b->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_abs.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_add.c b/crypto/userspace/libtommath/bn_mp_add.c
new file mode 100644
index 00000000000..be20644770d
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_add.c
@@ -0,0 +1,53 @@
+#include <tommath.h>
+#ifdef BN_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* high level addition (handles signs) */
+int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ int sa, sb, res;
+
+ /* get sign of both inputs */
+ sa = a->sign;
+ sb = b->sign;
+
+ /* handle two cases, not four */
+ if (sa == sb) {
+ /* both positive or both negative */
+ /* add their magnitudes, copy the sign */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+ /* one positive, the other negative */
+ /* subtract the one with the greater magnitude from */
+ /* the one of the lesser magnitude. The result gets */
+ /* the sign of the one with the greater magnitude. */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ c->sign = sb;
+ res = s_mp_sub (b, a, c);
+ } else {
+ c->sign = sa;
+ res = s_mp_sub (a, b, c);
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_add.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_add_d.c b/crypto/userspace/libtommath/bn_mp_add_d.c
new file mode 100644
index 00000000000..8ca36c1124f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_add_d.c
@@ -0,0 +1,112 @@
+#include <tommath.h>
+#ifdef BN_MP_ADD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* single digit addition */
+int
+mp_add_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ int res, ix, oldused;
+ mp_digit *tmpa, *tmpc, mu;
+
+ /* grow c as required */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* if a is negative and |a| >= b, call c = |a| - b */
+ if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
+ /* temporarily fix sign of a */
+ a->sign = MP_ZPOS;
+
+ /* c = |a| - b */
+ res = mp_sub_d(a, b, c);
+
+ /* fix sign */
+ a->sign = c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return res;
+ }
+
+ /* old number of used digits in c */
+ oldused = c->used;
+
+ /* sign always positive */
+ c->sign = MP_ZPOS;
+
+ /* source alias */
+ tmpa = a->dp;
+
+ /* destination alias */
+ tmpc = c->dp;
+
+ /* if a is positive */
+ if (a->sign == MP_ZPOS) {
+ /* add digit, after this we're propagating
+ * the carry.
+ */
+ *tmpc = *tmpa++ + b;
+ mu = *tmpc >> DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+
+ /* now handle rest of the digits */
+ for (ix = 1; ix < a->used; ix++) {
+ *tmpc = *tmpa++ + mu;
+ mu = *tmpc >> DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+ }
+ /* set final carry */
+ ix++;
+ *tmpc++ = mu;
+
+ /* setup size */
+ c->used = a->used + 1;
+ } else {
+ /* a was negative and |a| < b */
+ c->used = 1;
+
+ /* the result is a single digit */
+ if (a->used == 1) {
+ *tmpc++ = b - a->dp[0];
+ } else {
+ *tmpc++ = b;
+ }
+
+ /* setup count so the clearing of oldused
+ * can fall through correctly
+ */
+ ix = 1;
+ }
+
+ /* now zero to oldused */
+ while (ix++ < oldused) {
+ *tmpc++ = 0;
+ }
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_add_d.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_addmod.c b/crypto/userspace/libtommath/bn_mp_addmod.c
new file mode 100644
index 00000000000..6d8afe18c93
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_addmod.c
@@ -0,0 +1,41 @@
+#include <tommath.h>
+#ifdef BN_MP_ADDMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* d = a + b (mod c) */
+int
+mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_add (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_addmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_clamp.c b/crypto/userspace/libtommath/bn_mp_clamp.c
new file mode 100644
index 00000000000..359c2ff24d2
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_clamp.c
@@ -0,0 +1,44 @@
+#include <tommath.h>
+#ifdef BN_MP_CLAMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* trim unused digits
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast. Also fixes the sign if there
+ * are no more leading digits
+ */
+void
+mp_clamp (mp_int * a)
+{
+ /* decrease used while the most significant digit is
+ * zero.
+ */
+ while (a->used > 0 && a->dp[a->used - 1] == 0) {
+ --(a->used);
+ }
+
+ /* reset the sign flag if used == 0 */
+ if (a->used == 0) {
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_clamp.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_clear.c b/crypto/userspace/libtommath/bn_mp_clear.c
new file mode 100644
index 00000000000..a65f0a36c49
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_clear.c
@@ -0,0 +1,44 @@
+#include <tommath.h>
+#ifdef BN_MP_CLEAR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* clear one (frees) */
+void
+mp_clear (mp_int * a)
+{
+ int i;
+
+ /* only do anything if a hasn't been freed previously */
+ if (a->dp != NULL) {
+ /* first zero the digits */
+ for (i = 0; i < a->used; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* free ram */
+ XFREE(a->dp);
+
+ /* reset members to make debugging easier */
+ a->dp = NULL;
+ a->alloc = a->used = 0;
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_clear.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_clear_multi.c b/crypto/userspace/libtommath/bn_mp_clear_multi.c
new file mode 100644
index 00000000000..daaea79a3bd
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_clear_multi.c
@@ -0,0 +1,34 @@
+#include <tommath.h>
+#ifdef BN_MP_CLEAR_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include <stdarg.h>
+
+void mp_clear_multi(mp_int *mp, ...)
+{
+ mp_int* next_mp = mp;
+ va_list args;
+ va_start(args, mp);
+ while (next_mp != NULL) {
+ mp_clear(next_mp);
+ next_mp = va_arg(args, mp_int*);
+ }
+ va_end(args);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_clear_multi.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_cmp.c b/crypto/userspace/libtommath/bn_mp_cmp.c
new file mode 100644
index 00000000000..533f36bf931
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_cmp.c
@@ -0,0 +1,43 @@
+#include <tommath.h>
+#ifdef BN_MP_CMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* compare two ints (signed)*/
+int
+mp_cmp (mp_int * a, mp_int * b)
+{
+ /* compare based on sign */
+ if (a->sign != b->sign) {
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ } else {
+ return MP_GT;
+ }
+ }
+
+ /* compare digits */
+ if (a->sign == MP_NEG) {
+ /* if negative compare opposite direction */
+ return mp_cmp_mag(b, a);
+ } else {
+ return mp_cmp_mag(a, b);
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cmp.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_cmp_d.c b/crypto/userspace/libtommath/bn_mp_cmp_d.c
new file mode 100644
index 00000000000..724c1c36344
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_cmp_d.c
@@ -0,0 +1,44 @@
+#include <tommath.h>
+#ifdef BN_MP_CMP_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* compare a digit */
+int mp_cmp_d(mp_int * a, mp_digit b)
+{
+ /* compare based on sign */
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ }
+
+ /* compare based on magnitude */
+ if (a->used > 1) {
+ return MP_GT;
+ }
+
+ /* compare the only digit of a to b */
+ if (a->dp[0] > b) {
+ return MP_GT;
+ } else if (a->dp[0] < b) {
+ return MP_LT;
+ } else {
+ return MP_EQ;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_cmp_mag.c b/crypto/userspace/libtommath/bn_mp_cmp_mag.c
new file mode 100644
index 00000000000..693eb7cc729
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_cmp_mag.c
@@ -0,0 +1,55 @@
+#include <tommath.h>
+#ifdef BN_MP_CMP_MAG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* compare maginitude of two ints (unsigned) */
+int mp_cmp_mag (mp_int * a, mp_int * b)
+{
+ int n;
+ mp_digit *tmpa, *tmpb;
+
+ /* compare based on # of non-zero digits */
+ if (a->used > b->used) {
+ return MP_GT;
+ }
+
+ if (a->used < b->used) {
+ return MP_LT;
+ }
+
+ /* alias for a */
+ tmpa = a->dp + (a->used - 1);
+
+ /* alias for b */
+ tmpb = b->dp + (a->used - 1);
+
+ /* compare based on digits */
+ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+ if (*tmpa > *tmpb) {
+ return MP_GT;
+ }
+
+ if (*tmpa < *tmpb) {
+ return MP_LT;
+ }
+ }
+ return MP_EQ;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_mag.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_cnt_lsb.c b/crypto/userspace/libtommath/bn_mp_cnt_lsb.c
new file mode 100644
index 00000000000..66d1a74714b
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_cnt_lsb.c
@@ -0,0 +1,53 @@
+#include <tommath.h>
+#ifdef BN_MP_CNT_LSB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+static const int lnz[16] = {
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a)
+{
+ int x;
+ mp_digit q, qq;
+
+ /* easy out */
+ if (mp_iszero(a) == 1) {
+ return 0;
+ }
+
+ /* scan lower digits until non-zero */
+ for (x = 0; x < a->used && a->dp[x] == 0; x++);
+ q = a->dp[x];
+ x *= DIGIT_BIT;
+
+ /* now scan this digit until a 1 is found */
+ if ((q & 1) == 0) {
+ do {
+ qq = q & 15;
+ x += lnz[qq];
+ q >>= 4;
+ } while (qq == 0);
+ }
+ return x;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_cnt_lsb.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_copy.c b/crypto/userspace/libtommath/bn_mp_copy.c
new file mode 100644
index 00000000000..b0de16d8abf
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_copy.c
@@ -0,0 +1,68 @@
+#include <tommath.h>
+#ifdef BN_MP_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* copy, b = a */
+int
+mp_copy (mp_int * a, mp_int * b)
+{
+ int res, n;
+
+ /* if dst == src do nothing */
+ if (a == b) {
+ return MP_OKAY;
+ }
+
+ /* grow dest */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* zero b and copy the parameters over */
+ {
+ register mp_digit *tmpa, *tmpb;
+
+ /* pointer aliases */
+
+ /* source */
+ tmpa = a->dp;
+
+ /* destination */
+ tmpb = b->dp;
+
+ /* copy all the digits */
+ for (n = 0; n < a->used; n++) {
+ *tmpb++ = *tmpa++;
+ }
+
+ /* clear high digits */
+ for (; n < b->used; n++) {
+ *tmpb++ = 0;
+ }
+ }
+
+ /* copy used count and sign */
+ b->used = a->used;
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_copy.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_count_bits.c b/crypto/userspace/libtommath/bn_mp_count_bits.c
new file mode 100644
index 00000000000..8bc5657a333
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_count_bits.c
@@ -0,0 +1,45 @@
+#include <tommath.h>
+#ifdef BN_MP_COUNT_BITS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* returns the number of bits in an int */
+int
+mp_count_bits (mp_int * a)
+{
+ int r;
+ mp_digit q;
+
+ /* shortcut */
+ if (a->used == 0) {
+ return 0;
+ }
+
+ /* get number of digits and add that */
+ r = (a->used - 1) * DIGIT_BIT;
+
+ /* take the last digit and count the bits in it */
+ q = a->dp[a->used - 1];
+ while (q > ((mp_digit) 0)) {
+ ++r;
+ q >>= ((mp_digit) 1);
+ }
+ return r;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_count_bits.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_div.c b/crypto/userspace/libtommath/bn_mp_div.c
new file mode 100644
index 00000000000..723c8b503dd
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_div.c
@@ -0,0 +1,292 @@
+#include <tommath.h>
+#ifdef BN_MP_DIV_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+#ifdef BN_MP_DIV_SMALL
+
+/* slower bit-bang division... also smaller */
+int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int ta, tb, tq, q;
+ int res, n, n2;
+
+ /* is divisor zero ? */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+ /* init our temps */
+ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) {
+ return res;
+ }
+
+
+ mp_set(&tq, 1);
+ n = mp_count_bits(a) - mp_count_bits(b);
+ if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+ ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+
+ while (n-- >= 0) {
+ if (mp_cmp(&tb, &ta) != MP_GT) {
+ if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+ ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+ if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
+ ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* now q == quotient and ta == remainder */
+ n = a->sign;
+ n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+ if (c != NULL) {
+ mp_exch(c, &q);
+ c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+ }
+ if (d != NULL) {
+ mp_exch(d, &ta);
+ d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+ }
+LBL_ERR:
+ mp_clear_multi(&ta, &tb, &tq, &q, NULL);
+ return res;
+}
+
+#else
+
+/* integer signed division.
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int q, x, y, t1, t2;
+ int res, n, t, i, norm, neg;
+
+ /* is divisor zero ? */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+ if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
+ return res;
+ }
+ q.used = a->used + 2;
+
+ if ((res = mp_init (&t1)) != MP_OKAY) {
+ goto LBL_Q;
+ }
+
+ if ((res = mp_init (&t2)) != MP_OKAY) {
+ goto LBL_T1;
+ }
+
+ if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
+ goto LBL_T2;
+ }
+
+ if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
+ goto LBL_X;
+ }
+
+ /* fix the sign */
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+ x.sign = y.sign = MP_ZPOS;
+
+ /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+ norm = mp_count_bits(&y) % DIGIT_BIT;
+ if (norm < (int)(DIGIT_BIT-1)) {
+ norm = (DIGIT_BIT-1) - norm;
+ if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ } else {
+ norm = 0;
+ }
+
+ /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+ n = x.used - 1;
+ t = y.used - 1;
+
+ /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+ if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
+ goto LBL_Y;
+ }
+
+ while (mp_cmp (&x, &y) != MP_LT) {
+ ++(q.dp[n - t]);
+ if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ }
+
+ /* reset y by shifting it back down */
+ mp_rshd (&y, n - t);
+
+ /* step 3. for i from n down to (t + 1) */
+ for (i = n; i >= (t + 1); i--) {
+ if (i > x.used) {
+ continue;
+ }
+
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+ if (x.dp[i] == y.dp[t]) {
+ q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
+ } else {
+ mp_word tmp;
+ tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
+ tmp |= ((mp_word) x.dp[i - 1]);
+ tmp = word_div_int(tmp, (int)y.dp[t]);
+ if (tmp > (mp_word) MP_MASK)
+ tmp = MP_MASK;
+ q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
+ }
+
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
+ */
+ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
+ do {
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
+
+ /* find left hand */
+ mp_zero (&t1);
+ t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+ t1.dp[1] = y.dp[t];
+ t1.used = 2;
+ if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* find right hand */
+ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+ t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+ t2.dp[2] = x.dp[i];
+ t2.used = 3;
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+ if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+ if (x.sign == MP_NEG) {
+ if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
+ }
+ }
+
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
+ */
+
+ /* get sign before writing to c */
+ x.sign = x.used == 0 ? MP_ZPOS : a->sign;
+
+ if (c != NULL) {
+ mp_clamp (&q);
+ mp_exch (&q, c);
+ c->sign = neg;
+ }
+
+ if (d != NULL) {
+ mp_div_2d (&x, norm, &x, NULL);
+ mp_exch (&x, d);
+ }
+
+ res = MP_OKAY;
+
+LBL_Y:mp_clear (&y);
+LBL_X:mp_clear (&x);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+LBL_Q:mp_clear (&q);
+ return res;
+}
+
+#endif
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_div_2.c b/crypto/userspace/libtommath/bn_mp_div_2.c
new file mode 100644
index 00000000000..7ee3e5b70fd
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_div_2.c
@@ -0,0 +1,68 @@
+#include <tommath.h>
+#ifdef BN_MP_DIV_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = a/2 */
+int mp_div_2(mp_int * a, mp_int * b)
+{
+ int x, res, oldused;
+
+ /* copy */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+ {
+ register mp_digit r, rr, *tmpa, *tmpb;
+
+ /* source alias */
+ tmpa = a->dp + b->used - 1;
+
+ /* dest alias */
+ tmpb = b->dp + b->used - 1;
+
+ /* carry */
+ r = 0;
+ for (x = b->used - 1; x >= 0; x--) {
+ /* get the carry for the next iteration */
+ rr = *tmpa & 1;
+
+ /* shift the current digit, add in carry and store */
+ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+ /* forward carry to next iteration */
+ r = rr;
+ }
+
+ /* zero excess digits */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ mp_clamp (b);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_2.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_div_2d.c b/crypto/userspace/libtommath/bn_mp_div_2d.c
new file mode 100644
index 00000000000..4f7fa59e3f3
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_div_2d.c
@@ -0,0 +1,97 @@
+#include <tommath.h>
+#ifdef BN_MP_DIV_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
+int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+ mp_digit D, r, rr;
+ int x, res;
+ mp_int t;
+
+
+ /* if the shift count is <= 0 then we do no work */
+ if (b <= 0) {
+ res = mp_copy (a, c);
+ if (d != NULL) {
+ mp_zero (d);
+ }
+ return res;
+ }
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ /* get the remainder */
+ if (d != NULL) {
+ if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= (int)DIGIT_BIT) {
+ mp_rshd (c, b / DIGIT_BIT);
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ D = (mp_digit) (b % DIGIT_BIT);
+ if (D != 0) {
+ register mp_digit *tmpc, mask, shift;
+
+ /* mask */
+ mask = (((mp_digit)1) << D) - 1;
+
+ /* shift for lsb */
+ shift = DIGIT_BIT - D;
+
+ /* alias */
+ tmpc = c->dp + (c->used - 1);
+
+ /* carry */
+ r = 0;
+ for (x = c->used - 1; x >= 0; x--) {
+ /* get the lower bits of this word in a temp */
+ rr = *tmpc & mask;
+
+ /* shift the current word and mix in the carry bits from the previous word */
+ *tmpc = (*tmpc >> D) | (r << shift);
+ --tmpc;
+
+ /* set the carry to the carry bits of the current word found above */
+ r = rr;
+ }
+ }
+ mp_clamp (c);
+ if (d != NULL) {
+ mp_exch (&t, d);
+ }
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_2d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_div_3.c b/crypto/userspace/libtommath/bn_mp_div_3.c
new file mode 100644
index 00000000000..608e759e366
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_div_3.c
@@ -0,0 +1,79 @@
+#include <tommath.h>
+#ifdef BN_MP_DIV_3_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* divide by three (based on routine from MPI and the GMP manual) */
+int
+mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
+{
+ mp_int q;
+ mp_word w, t;
+ mp_digit b;
+ int res, ix;
+
+ /* b = 2**DIGIT_BIT / 3 */
+ b = word_div_int (((mp_word)1) << DIGIT_BIT, 3);
+
+ if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return res;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used - 1; ix >= 0; ix--) {
+ w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+ if (w >= 3) {
+ /* multiply w by [1/3] */
+ t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
+
+ /* now subtract 3 * [w/3] from w, to get the remainder */
+ w -= t+t+t;
+
+ /* fixup the remainder as required since
+ * the optimization is not exact.
+ */
+ while (w >= 3) {
+ t += 1;
+ w -= 3;
+ }
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = (mp_digit)t;
+ }
+
+ /* [optional] store the remainder */
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ /* [optional] store the quotient */
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_3.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_div_d.c b/crypto/userspace/libtommath/bn_mp_div_d.c
new file mode 100644
index 00000000000..63efc2cfa69
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_div_d.c
@@ -0,0 +1,115 @@
+#include <tommath.h>
+#ifdef BN_MP_DIV_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+static int s_is_power_of_two(mp_digit b, int *p)
+{
+ int x;
+
+ /* fast return if no power of two */
+ if ((b==0) || (b & (b-1))) {
+ return 0;
+ }
+
+ for (x = 0; x < DIGIT_BIT; x++) {
+ if (b == (((mp_digit)1)<<x)) {
+ *p = x;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* single digit division (based on routine from MPI) */
+int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
+{
+ mp_int q;
+ mp_word w;
+ mp_digit t;
+ int res, ix;
+
+ /* cannot divide by zero */
+ if (b == 0) {
+ return MP_VAL;
+ }
+
+ /* quick outs */
+ if (b == 1 || mp_iszero(a) == 1) {
+ if (d != NULL) {
+ *d = 0;
+ }
+ if (c != NULL) {
+ return mp_copy(a, c);
+ }
+ return MP_OKAY;
+ }
+
+ /* power of two ? */
+ if (s_is_power_of_two(b, &ix) == 1) {
+ if (d != NULL) {
+ *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1);
+ }
+ if (c != NULL) {
+ return mp_div_2d(a, ix, c, NULL);
+ }
+ return MP_OKAY;
+ }
+
+#ifdef BN_MP_DIV_3_C
+ /* three? */
+ if (b == 3) {
+ return mp_div_3(a, c, d);
+ }
+#endif
+
+ /* no easy answer [c'est la vie]. Just division */
+ if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return res;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used - 1; ix >= 0; ix--) {
+ w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+ if (w >= b) {
+ t = (mp_digit)(word_div_int(w, b));
+ w -= ((mp_word)t) * ((mp_word)b);
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = (mp_digit)t;
+ }
+
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_div_d.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2007/01/09 04:44:32 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_dr_is_modulus.c b/crypto/userspace/libtommath/bn_mp_dr_is_modulus.c
new file mode 100644
index 00000000000..52373440d83
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_dr_is_modulus.c
@@ -0,0 +1,43 @@
+#include <tommath.h>
+#ifdef BN_MP_DR_IS_MODULUS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if a number is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a)
+{
+ int ix;
+
+ /* must be at least two digits */
+ if (a->used < 2) {
+ return 0;
+ }
+
+ /* must be of the form b**k - a [a <= b] so all
+ * but the first digit must be equal to -1 (mod b).
+ */
+ for (ix = 1; ix < a->used; ix++) {
+ if (a->dp[ix] != MP_MASK) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_dr_is_modulus.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_dr_reduce.c b/crypto/userspace/libtommath/bn_mp_dr_reduce.c
new file mode 100644
index 00000000000..e60b5784f16
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_dr_reduce.c
@@ -0,0 +1,94 @@
+#include <tommath.h>
+#ifdef BN_MP_DR_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
+ *
+ * Based on algorithm from the paper
+ *
+ * "Generating Efficient Primes for Discrete Log Cryptosystems"
+ * Chae Hoon Lim, Pil Joong Lee,
+ * POSTECH Information Research Laboratories
+ *
+ * The modulus must be of a special format [see manual]
+ *
+ * Has been modified to use algorithm 7.10 from the LTM book instead
+ *
+ * Input x must be in the range 0 <= x <= (n-1)**2
+ */
+int
+mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
+{
+ int err, i, m;
+ mp_word r;
+ mp_digit mu, *tmpx1, *tmpx2;
+
+ /* m = digits in modulus */
+ m = n->used;
+
+ /* ensure that "x" has at least 2m digits */
+ if (x->alloc < m + m) {
+ if ((err = mp_grow (x, m + m)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+/* top of loop, this is where the code resumes if
+ * another reduction pass is required.
+ */
+top:
+ /* aliases for digits */
+ /* alias for lower half of x */
+ tmpx1 = x->dp;
+
+ /* alias for upper half of x, or x/B**m */
+ tmpx2 = x->dp + m;
+
+ /* set carry to zero */
+ mu = 0;
+
+ /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
+ for (i = 0; i < m; i++) {
+ r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
+ *tmpx1++ = (mp_digit)(r & MP_MASK);
+ mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
+ }
+
+ /* set final carry */
+ *tmpx1++ = mu;
+
+ /* zero words above m */
+ for (i = m + 1; i < x->used; i++) {
+ *tmpx1++ = 0;
+ }
+
+ /* clamp, sub and return */
+ mp_clamp (x);
+
+ /* if x >= n then subtract and reduce again
+ * Each successive "recursion" makes the input smaller and smaller.
+ */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ s_mp_sub(x, n, x);
+ goto top;
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_dr_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_dr_setup.c b/crypto/userspace/libtommath/bn_mp_dr_setup.c
new file mode 100644
index 00000000000..1d7d856ef0a
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_dr_setup.c
@@ -0,0 +1,32 @@
+#include <tommath.h>
+#ifdef BN_MP_DR_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines the setup value */
+void mp_dr_setup(mp_int *a, mp_digit *d)
+{
+ /* the casts are required if DIGIT_BIT is one less than
+ * the number of bits in a mp_digit [e.g. DIGIT_BIT==31]
+ */
+ *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) -
+ ((mp_word)a->dp[0]));
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_dr_setup.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_exch.c b/crypto/userspace/libtommath/bn_mp_exch.c
new file mode 100644
index 00000000000..38574e0a5e9
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_exch.c
@@ -0,0 +1,34 @@
+#include <tommath.h>
+#ifdef BN_MP_EXCH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* swap the elements of two integers, for cases where you can't simply swap the
+ * mp_int pointers around
+ */
+void
+mp_exch (mp_int * a, mp_int * b)
+{
+ mp_int t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exch.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_expt_d.c b/crypto/userspace/libtommath/bn_mp_expt_d.c
new file mode 100644
index 00000000000..4bdc2d13a69
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_expt_d.c
@@ -0,0 +1,57 @@
+#include <tommath.h>
+#ifdef BN_MP_EXPT_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* calculate c = a**b using a square-multiply algorithm */
+int mp_expt_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ int res, x;
+ mp_int g;
+
+ if ((res = mp_init_copy (&g, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* set initial result */
+ mp_set (c, 1);
+
+ for (x = 0; x < (int) DIGIT_BIT; x++) {
+ /* square */
+ if ((res = mp_sqr (c, c)) != MP_OKAY) {
+ mp_clear (&g);
+ return res;
+ }
+
+ /* if the bit is set multiply */
+ if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) {
+ if ((res = mp_mul (c, &g, c)) != MP_OKAY) {
+ mp_clear (&g);
+ return res;
+ }
+ }
+
+ /* shift to next bit */
+ b <<= 1;
+ }
+
+ mp_clear (&g);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_expt_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_exptmod.c b/crypto/userspace/libtommath/bn_mp_exptmod.c
new file mode 100644
index 00000000000..023191657ab
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_exptmod.c
@@ -0,0 +1,112 @@
+#include <tommath.h>
+#ifdef BN_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions. Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+ int dr;
+
+ /* modulus P must be positive */
+ if (P->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* if exponent X is negative we have to recurse */
+ if (X->sign == MP_NEG) {
+#ifdef BN_MP_INVMOD_C
+ mp_int tmpG, tmpX;
+ int err;
+
+ /* first compute 1/G mod P */
+ if ((err = mp_init(&tmpG)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+
+ /* now get |X| */
+ if ((err = mp_init(&tmpX)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+ }
+
+ /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+ err = mp_exptmod(&tmpG, &tmpX, P, Y);
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+#else
+ /* no invmod */
+ return MP_VAL;
+#endif
+ }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
+ if (mp_reduce_is_2k_l(P) == MP_YES) {
+ return s_mp_exptmod(G, X, P, Y, 1);
+ }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+ /* is it a DR modulus? */
+ dr = mp_dr_is_modulus(P);
+#else
+ /* default to no */
+ dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+ /* if not, is it a unrestricted DR modulus? */
+ if (dr == 0) {
+ dr = mp_reduce_is_2k(P) << 1;
+ }
+#endif
+
+ /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+ if (mp_isodd (P) == 1 || dr != 0) {
+ return mp_exptmod_fast (G, X, P, Y, dr);
+ } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+ /* otherwise use the generic Barrett reduction technique */
+ return s_mp_exptmod (G, X, P, Y, 0);
+#else
+ /* no exptmod for evens */
+ return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+ }
+#endif
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_exptmod_fast.c b/crypto/userspace/libtommath/bn_mp_exptmod_fast.c
new file mode 100644
index 00000000000..2a3b3c9e816
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_exptmod_fast.c
@@ -0,0 +1,321 @@
+#include <tommath.h>
+#ifdef BN_MP_EXPTMOD_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+#ifdef MP_LOW_MEM
+ #define TAB_SIZE 32
+#else
+ #define TAB_SIZE 256
+#endif
+
+int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res;
+ mp_digit buf, mp;
+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+ /* use a pointer to the reduction algorithm. This allows us to use
+ * one of many reduction algorithms without modding the guts of
+ * the code with if statements everywhere.
+ */
+ int (*redux)(mp_int*,mp_int*,mp_digit);
+
+ /* find window size */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear (&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* determine and setup reduction code */
+ if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+ /* now setup montgomery */
+ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+
+ /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+ if (((P->used * 2 + 1) < MP_WARRAY) &&
+ P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ redux = fast_mp_montgomery_reduce;
+ } else
+#endif
+ {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+ /* use slower baseline Montgomery method */
+ redux = mp_montgomery_reduce;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ }
+ } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+ /* setup DR reduction for moduli of the form B**k - b */
+ mp_dr_setup(P, &mp);
+ redux = mp_dr_reduce;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+ /* setup DR reduction for moduli of the form 2**k - b */
+ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+ redux = mp_reduce_2k;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ }
+
+ /* setup result */
+ if ((err = mp_init (&res)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+ /* create M table
+ *
+
+ *
+ * The first half of the table is not computed though accept for M[0] and M[1]
+ */
+
+ if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+ /* now we need R mod m */
+ if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+#else
+ err = MP_VAL;
+ goto LBL_RES;
+#endif
+
+ /* now set M[1] to G * R mod m */
+ if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ } else {
+ mp_set(&res, 1);
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* create upper table */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits so break */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* get next bit of the window */
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+ if (redmode == 0) {
+ /* fixup result if Montgomery reduction is used
+ * recall that any value in a Montgomery system is
+ * actually multiplied by R mod n. So we have
+ * to reduce one more time to cancel out the factor
+ * of R.
+ */
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* swap res with Y */
+ mp_exch (&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear (&M[x]);
+ }
+ return err;
+}
+#endif
+
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod_fast.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_gcd.c b/crypto/userspace/libtommath/bn_mp_gcd.c
new file mode 100644
index 00000000000..b39ba9041db
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_gcd.c
@@ -0,0 +1,105 @@
+#include <tommath.h>
+#ifdef BN_MP_GCD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Greatest Common Divisor using the binary method */
+int mp_gcd (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int u, v;
+ int k, u_lsb, v_lsb, res;
+
+ /* either zero than gcd is the largest */
+ if (mp_iszero (a) == MP_YES) {
+ return mp_abs (b, c);
+ }
+ if (mp_iszero (b) == MP_YES) {
+ return mp_abs (a, c);
+ }
+
+ /* get copies of a and b we can modify */
+ if ((res = mp_init_copy (&u, a)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_init_copy (&v, b)) != MP_OKAY) {
+ goto LBL_U;
+ }
+
+ /* must be positive for the remainder of the algorithm */
+ u.sign = v.sign = MP_ZPOS;
+
+ /* B1. Find the common power of two for u and v */
+ u_lsb = mp_cnt_lsb(&u);
+ v_lsb = mp_cnt_lsb(&v);
+ k = MIN(u_lsb, v_lsb);
+
+ if (k > 0) {
+ /* divide the power of two out */
+ if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* divide any remaining factors of two out */
+ if (u_lsb != k) {
+ if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ if (v_lsb != k) {
+ if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ while (mp_iszero(&v) == 0) {
+ /* make sure v is the largest */
+ if (mp_cmp_mag(&u, &v) == MP_GT) {
+ /* swap u and v to make sure v is >= u */
+ mp_exch(&u, &v);
+ }
+
+ /* subtract smallest from largest */
+ if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ /* Divide out all factors of two */
+ if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* multiply by 2**k which we divided out at the beginning */
+ if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ c->sign = MP_ZPOS;
+ res = MP_OKAY;
+LBL_V:mp_clear (&u);
+LBL_U:mp_clear (&v);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_gcd.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_get_int.c b/crypto/userspace/libtommath/bn_mp_get_int.c
new file mode 100644
index 00000000000..17162e2bf1f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_get_int.c
@@ -0,0 +1,45 @@
+#include <tommath.h>
+#ifdef BN_MP_GET_INT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* get the lower 32-bits of an mp_int */
+unsigned long mp_get_int(mp_int * a)
+{
+ int i;
+ unsigned long res;
+
+ if (a->used == 0) {
+ return 0;
+ }
+
+ /* get number of digits of the lsb we have to read */
+ i = MIN(a->used,(int)((sizeof(unsigned long)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1;
+
+ /* get most significant digit of result */
+ res = DIGIT(a,i);
+
+ while (--i >= 0) {
+ res = (res << DIGIT_BIT) | DIGIT(a,i);
+ }
+
+ /* force result to 32-bits always so it is consistent on non 32-bit platforms */
+ return res & 0xFFFFFFFFUL;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_get_int.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_grow.c b/crypto/userspace/libtommath/bn_mp_grow.c
new file mode 100644
index 00000000000..cf2b949b248
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_grow.c
@@ -0,0 +1,57 @@
+#include <tommath.h>
+#ifdef BN_MP_GROW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* grow as required */
+int mp_grow (mp_int * a, int size)
+{
+ int i;
+ mp_digit *tmp;
+
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ /* ensure there are always at least MP_PREC digits extra on top */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+ /* reallocate the array a->dp
+ *
+ * We store the return in a temporary variable
+ * in case the operation failed we don't want
+ * to overwrite the dp member of a.
+ */
+ tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
+ if (tmp == NULL) {
+ /* reallocation failed but "a" is still valid [can be freed] */
+ return MP_MEM;
+ }
+
+ /* reallocation succeeded so set a->dp */
+ a->dp = tmp;
+
+ /* zero excess digits */
+ i = a->alloc;
+ a->alloc = size;
+ for (; i < a->alloc; i++) {
+ a->dp[i] = 0;
+ }
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_grow.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_init.c b/crypto/userspace/libtommath/bn_mp_init.c
new file mode 100644
index 00000000000..8be27f5696a
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_init.c
@@ -0,0 +1,46 @@
+#include <tommath.h>
+#ifdef BN_MP_INIT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* init a new mp_int */
+int mp_init (mp_int * a)
+{
+ int i;
+
+ /* allocate memory required and clear it */
+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the digits to zero */
+ for (i = 0; i < MP_PREC; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* set the used to zero, allocated digits to the default precision
+ * and sign to positive */
+ a->used = 0;
+ a->alloc = MP_PREC;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_init_copy.c b/crypto/userspace/libtommath/bn_mp_init_copy.c
new file mode 100644
index 00000000000..0160811affb
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_init_copy.c
@@ -0,0 +1,32 @@
+#include <tommath.h>
+#ifdef BN_MP_INIT_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* creates "a" then copies b into it */
+int mp_init_copy (mp_int * a, mp_int * b)
+{
+ int res;
+
+ if ((res = mp_init (a)) != MP_OKAY) {
+ return res;
+ }
+ return mp_copy (b, a);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_copy.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_init_multi.c b/crypto/userspace/libtommath/bn_mp_init_multi.c
new file mode 100644
index 00000000000..59dc3a9ea75
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_init_multi.c
@@ -0,0 +1,59 @@
+#include <tommath.h>
+#ifdef BN_MP_INIT_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#include <stdarg.h>
+
+int mp_init_multi(mp_int *mp, ...)
+{
+ mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
+ int n = 0; /* Number of ok inits */
+ mp_int* cur_arg = mp;
+ va_list args;
+
+ va_start(args, mp); /* init args to next argument from caller */
+ while (cur_arg != NULL) {
+ if (mp_init(cur_arg) != MP_OKAY) {
+ /* Oops - error! Back-track and mp_clear what we already
+ succeeded in init-ing, then return error.
+ */
+ va_list clean_args;
+
+ /* end the current list */
+ va_end(args);
+
+ /* now start cleaning up */
+ cur_arg = mp;
+ va_start(clean_args, mp);
+ while (n--) {
+ mp_clear(cur_arg);
+ cur_arg = va_arg(clean_args, mp_int*);
+ }
+ va_end(clean_args);
+ res = MP_MEM;
+ break;
+ }
+ n++;
+ cur_arg = va_arg(args, mp_int*);
+ }
+ va_end(args);
+ return res; /* Assumed ok, if error flagged above. */
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_multi.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_init_set.c b/crypto/userspace/libtommath/bn_mp_init_set.c
new file mode 100644
index 00000000000..34edad92ff0
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_init_set.c
@@ -0,0 +1,32 @@
+#include <tommath.h>
+#ifdef BN_MP_INIT_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* initialize and set a digit */
+int mp_init_set (mp_int * a, mp_digit b)
+{
+ int err;
+ if ((err = mp_init(a)) != MP_OKAY) {
+ return err;
+ }
+ mp_set(a, b);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_set.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_init_set_int.c b/crypto/userspace/libtommath/bn_mp_init_set_int.c
new file mode 100644
index 00000000000..5c559931520
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_init_set_int.c
@@ -0,0 +1,31 @@
+#include <tommath.h>
+#ifdef BN_MP_INIT_SET_INT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* initialize and set a digit */
+int mp_init_set_int (mp_int * a, unsigned long b)
+{
+ int err;
+ if ((err = mp_init(a)) != MP_OKAY) {
+ return err;
+ }
+ return mp_set_int(a, b);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_set_int.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_init_size.c b/crypto/userspace/libtommath/bn_mp_init_size.c
new file mode 100644
index 00000000000..8e014183a3e
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_init_size.c
@@ -0,0 +1,48 @@
+#include <tommath.h>
+#ifdef BN_MP_INIT_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* init an mp_init for a given size */
+int mp_init_size (mp_int * a, int size)
+{
+ int x;
+
+ /* pad size so there are always extra digits */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+ /* alloc mem */
+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the members */
+ a->used = 0;
+ a->alloc = size;
+ a->sign = MP_ZPOS;
+
+ /* zero the digits */
+ for (x = 0; x < size; x++) {
+ a->dp[x] = 0;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_init_size.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_invmod.c b/crypto/userspace/libtommath/bn_mp_invmod.c
new file mode 100644
index 00000000000..154651468fb
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_invmod.c
@@ -0,0 +1,43 @@
+#include <tommath.h>
+#ifdef BN_MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* hac 14.61, pp608 */
+int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ /* b cannot be negative */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+#ifdef BN_FAST_MP_INVMOD_C
+ /* if the modulus is odd we can use a faster routine instead */
+ if (mp_isodd (b) == 1) {
+ return fast_mp_invmod (a, b, c);
+ }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+ return mp_invmod_slow(a, b, c);
+#endif
+
+ return MP_VAL;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_invmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_invmod_slow.c b/crypto/userspace/libtommath/bn_mp_invmod_slow.c
new file mode 100644
index 00000000000..eedd47dcf13
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_invmod_slow.c
@@ -0,0 +1,175 @@
+#include <tommath.h>
+#ifdef BN_MP_INVMOD_SLOW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* hac 14.61, pp608 */
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, A, B, C, D;
+ int res;
+
+ /* b cannot be negative */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+ /* init temps */
+ if ((res = mp_init_multi(&x, &y, &u, &v,
+ &A, &B, &C, &D, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* x = a, y = b */
+ if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 2. [modified] if x,y are both even then return an error! */
+ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set (&A, 1);
+ mp_set (&D, 1);
+
+top:
+ /* 4. while u is even do */
+ while (mp_iseven (&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if A or B is odd then */
+ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+ /* A = (A+y)/2, B = (B-x)/2 */
+ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* A = A/2, B = B/2 */
+ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven (&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if C or D is odd then */
+ if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
+ /* C = (C+y)/2, D = (D-x)/2 */
+ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* C = C/2, D = D/2 */
+ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp (&u, &v) != MP_LT) {
+ /* u = u - v, A = A - C, B = B - D */
+ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, C = C - A, D = D - B */
+ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* if not zero goto step 4 */
+ if (mp_iszero (&u) == 0)
+ goto top;
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d (&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* if its too low */
+ while (mp_cmp_d(&C, 0) == MP_LT) {
+ if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&C, b) != MP_LT) {
+ if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* C is now the inverse */
+ mp_exch (&C, c);
+ res = MP_OKAY;
+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_invmod_slow.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_is_square.c b/crypto/userspace/libtommath/bn_mp_is_square.c
new file mode 100644
index 00000000000..50c524444ec
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_is_square.c
@@ -0,0 +1,109 @@
+#include <tommath.h>
+#ifdef BN_MP_IS_SQUARE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Check if remainders are possible squares - fast exclude non-squares */
+static const char rem_128[128] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1
+};
+
+static const char rem_105[105] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1
+};
+
+/* Store non-zero to ret if arg is square, and zero if not */
+int mp_is_square(mp_int *arg,int *ret)
+{
+ int res;
+ mp_digit c;
+ mp_int t;
+ unsigned long r;
+
+ /* Default to Non-square :) */
+ *ret = MP_NO;
+
+ if (arg->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* digits used? (TSD) */
+ if (arg->used == 0) {
+ return MP_OKAY;
+ }
+
+ /* First check mod 128 (suppose that DIGIT_BIT is at least 7) */
+ if (rem_128[127 & DIGIT(arg,0)] == 1) {
+ return MP_OKAY;
+ }
+
+ /* Next check mod 105 (3*5*7) */
+ if ((res = mp_mod_d(arg,105,&c)) != MP_OKAY) {
+ return res;
+ }
+ if (rem_105[c] == 1) {
+ return MP_OKAY;
+ }
+
+
+ if ((res = mp_init_set_int(&t,11L*13L*17L*19L*23L*29L*31L)) != MP_OKAY) {
+ return res;
+ }
+ if ((res = mp_mod(arg,&t,&t)) != MP_OKAY) {
+ goto ERR;
+ }
+ r = mp_get_int(&t);
+ /* Check for other prime modules, note it's not an ERROR but we must
+ * free "t" so the easiest way is to goto ERR. We know that res
+ * is already equal to MP_OKAY from the mp_mod call
+ */
+ if ( (1L<<(r%11)) & 0x5C4L ) goto ERR;
+ if ( (1L<<(r%13)) & 0x9E4L ) goto ERR;
+ if ( (1L<<(r%17)) & 0x5CE8L ) goto ERR;
+ if ( (1L<<(r%19)) & 0x4F50CL ) goto ERR;
+ if ( (1L<<(r%23)) & 0x7ACCA0L ) goto ERR;
+ if ( (1L<<(r%29)) & 0xC2EDD0CL ) goto ERR;
+ if ( (1L<<(r%31)) & 0x6DE2B848L ) goto ERR;
+
+ /* Final check - is sqr(sqrt(arg)) == arg ? */
+ if ((res = mp_sqrt(arg,&t)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sqr(&t,&t)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ *ret = (mp_cmp_mag(&t,arg) == MP_EQ) ? MP_YES : MP_NO;
+ERR:mp_clear(&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_is_square.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_karatsuba_mul.c b/crypto/userspace/libtommath/bn_mp_karatsuba_mul.c
new file mode 100644
index 00000000000..8ea2c2792a9
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_karatsuba_mul.c
@@ -0,0 +1,167 @@
+#include <tommath.h>
+#ifdef BN_MP_KARATSUBA_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* c = |a| * |b| using Karatsuba Multiplication using
+ * three half size multiplications
+ *
+ * Let B represent the radix [e.g. 2**DIGIT_BIT] and
+ * let n represent half of the number of digits in
+ * the min(a,b)
+ *
+ * a = a1 * B**n + a0
+ * b = b1 * B**n + b0
+ *
+ * Then, a * b =>
+ a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0
+ *
+ * Note that a1b1 and a0b0 are used twice and only need to be
+ * computed once. So in total three half size (half # of
+ * digit) multiplications are performed, a0b0, a1b1 and
+ * (a1+b1)(a0+b0)
+ *
+ * Note that a multiplication of half the digits requires
+ * 1/4th the number of single precision multiplications so in
+ * total after one call 25% of the single precision multiplications
+ * are saved. Note also that the call to mp_mul can end up back
+ * in this function if the a0, a1, b0, or b1 are above the threshold.
+ * This is known as divide-and-conquer and leads to the famous
+ * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than
+ * the standard O(N**2) that the baseline/comba methods use.
+ * Generally though the overhead of this method doesn't pay off
+ * until a certain size (N ~ 80) is reached.
+ */
+int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x0, x1, y0, y1, t1, x0y0, x1y1;
+ int B, err;
+
+ /* default the return code to an error */
+ err = MP_MEM;
+
+ /* min # of digits */
+ B = MIN (a->used, b->used);
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if (mp_init_size (&x0, B) != MP_OKAY)
+ goto ERR;
+ if (mp_init_size (&x1, a->used - B) != MP_OKAY)
+ goto X0;
+ if (mp_init_size (&y0, B) != MP_OKAY)
+ goto X1;
+ if (mp_init_size (&y1, b->used - B) != MP_OKAY)
+ goto Y0;
+
+ /* init temps */
+ if (mp_init_size (&t1, B * 2) != MP_OKAY)
+ goto Y1;
+ if (mp_init_size (&x0y0, B * 2) != MP_OKAY)
+ goto T1;
+ if (mp_init_size (&x1y1, B * 2) != MP_OKAY)
+ goto X0Y0;
+
+ /* now shift the digits */
+ x0.used = y0.used = B;
+ x1.used = a->used - B;
+ y1.used = b->used - B;
+
+ {
+ register int x;
+ register mp_digit *tmpa, *tmpb, *tmpx, *tmpy;
+
+ /* we copy the digits directly instead of using higher level functions
+ * since we also need to shift the digits
+ */
+ tmpa = a->dp;
+ tmpb = b->dp;
+
+ tmpx = x0.dp;
+ tmpy = y0.dp;
+ for (x = 0; x < B; x++) {
+ *tmpx++ = *tmpa++;
+ *tmpy++ = *tmpb++;
+ }
+
+ tmpx = x1.dp;
+ for (x = B; x < a->used; x++) {
+ *tmpx++ = *tmpa++;
+ }
+
+ tmpy = y1.dp;
+ for (x = B; x < b->used; x++) {
+ *tmpy++ = *tmpb++;
+ }
+ }
+
+ /* only need to clamp the lower words since by definition the
+ * upper words x1/y1 must have a known number of digits
+ */
+ mp_clamp (&x0);
+ mp_clamp (&y0);
+
+ /* now calc the products x0y0 and x1y1 */
+ /* after this x0 is no longer required, free temp [x0==t2]! */
+ if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY)
+ goto X1Y1; /* x0y0 = x0*y0 */
+ if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY)
+ goto X1Y1; /* x1y1 = x1*y1 */
+
+ /* now calc x1+x0 and y1+y0 */
+ if (s_mp_add (&x1, &x0, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = x1 - x0 */
+ if (s_mp_add (&y1, &y0, &x0) != MP_OKAY)
+ goto X1Y1; /* t2 = y1 - y0 */
+ if (mp_mul (&t1, &x0, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */
+
+ /* add x0y0 */
+ if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY)
+ goto X1Y1; /* t2 = x0y0 + x1y1 */
+ if (s_mp_sub (&t1, &x0, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */
+
+ /* shift by B */
+ if (mp_lshd (&t1, B) != MP_OKAY)
+ goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
+ if (mp_lshd (&x1y1, B * 2) != MP_OKAY)
+ goto X1Y1; /* x1y1 = x1y1 << 2*B */
+
+ if (mp_add (&x0y0, &t1, &t1) != MP_OKAY)
+ goto X1Y1; /* t1 = x0y0 + t1 */
+ if (mp_add (&t1, &x1y1, c) != MP_OKAY)
+ goto X1Y1; /* t1 = x0y0 + t1 + x1y1 */
+
+ /* Algorithm succeeded set the return code to MP_OKAY */
+ err = MP_OKAY;
+
+X1Y1:mp_clear (&x1y1);
+X0Y0:mp_clear (&x0y0);
+T1:mp_clear (&t1);
+Y1:mp_clear (&y1);
+Y0:mp_clear (&y0);
+X1:mp_clear (&x1);
+X0:mp_clear (&x0);
+ERR:
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_mul.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_karatsuba_sqr.c b/crypto/userspace/libtommath/bn_mp_karatsuba_sqr.c
new file mode 100644
index 00000000000..a5e198be12f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_karatsuba_sqr.c
@@ -0,0 +1,121 @@
+#include <tommath.h>
+#ifdef BN_MP_KARATSUBA_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Karatsuba squaring, computes b = a*a using three
+ * half size squarings
+ *
+ * See comments of karatsuba_mul for details. It
+ * is essentially the same algorithm but merely
+ * tuned to perform recursive squarings.
+ */
+int mp_karatsuba_sqr (mp_int * a, mp_int * b)
+{
+ mp_int x0, x1, t1, t2, x0x0, x1x1;
+ int B, err;
+
+ err = MP_MEM;
+
+ /* min # of digits */
+ B = a->used;
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if (mp_init_size (&x0, B) != MP_OKAY)
+ goto ERR;
+ if (mp_init_size (&x1, a->used - B) != MP_OKAY)
+ goto X0;
+
+ /* init temps */
+ if (mp_init_size (&t1, a->used * 2) != MP_OKAY)
+ goto X1;
+ if (mp_init_size (&t2, a->used * 2) != MP_OKAY)
+ goto T1;
+ if (mp_init_size (&x0x0, B * 2) != MP_OKAY)
+ goto T2;
+ if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY)
+ goto X0X0;
+
+ {
+ register int x;
+ register mp_digit *dst, *src;
+
+ src = a->dp;
+
+ /* now shift the digits */
+ dst = x0.dp;
+ for (x = 0; x < B; x++) {
+ *dst++ = *src++;
+ }
+
+ dst = x1.dp;
+ for (x = B; x < a->used; x++) {
+ *dst++ = *src++;
+ }
+ }
+
+ x0.used = B;
+ x1.used = a->used - B;
+
+ mp_clamp (&x0);
+
+ /* now calc the products x0*x0 and x1*x1 */
+ if (mp_sqr (&x0, &x0x0) != MP_OKAY)
+ goto X1X1; /* x0x0 = x0*x0 */
+ if (mp_sqr (&x1, &x1x1) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1*x1 */
+
+ /* now calc (x1+x0)**2 */
+ if (s_mp_add (&x1, &x0, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = x1 - x0 */
+ if (mp_sqr (&t1, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */
+
+ /* add x0y0 */
+ if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY)
+ goto X1X1; /* t2 = x0x0 + x1x1 */
+ if (s_mp_sub (&t1, &t2, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */
+
+ /* shift by B */
+ if (mp_lshd (&t1, B) != MP_OKAY)
+ goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<<B */
+ if (mp_lshd (&x1x1, B * 2) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1x1 << 2*B */
+
+ if (mp_add (&x0x0, &t1, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = x0x0 + t1 */
+ if (mp_add (&t1, &x1x1, b) != MP_OKAY)
+ goto X1X1; /* t1 = x0x0 + t1 + x1x1 */
+
+ err = MP_OKAY;
+
+X1X1:mp_clear (&x1x1);
+X0X0:mp_clear (&x0x0);
+T2:mp_clear (&t2);
+T1:mp_clear (&t1);
+X1:mp_clear (&x1);
+X0:mp_clear (&x0);
+ERR:
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_sqr.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_lcm.c b/crypto/userspace/libtommath/bn_mp_lcm.c
new file mode 100644
index 00000000000..781eef5659e
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_lcm.c
@@ -0,0 +1,60 @@
+#include <tommath.h>
+#ifdef BN_MP_LCM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes least common multiple as |a*b|/(a, b) */
+int mp_lcm (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res;
+ mp_int t1, t2;
+
+
+ if ((res = mp_init_multi (&t1, &t2, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* t1 = get the GCD of the two inputs */
+ if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) {
+ goto LBL_T;
+ }
+
+ /* divide the smallest by the GCD */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ /* store quotient in t2 such that t2 * b is the LCM */
+ if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ res = mp_mul(b, &t2, c);
+ } else {
+ /* store quotient in t2 such that t2 * a is the LCM */
+ if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ res = mp_mul(a, &t2, c);
+ }
+
+ /* fix the sign to positive */
+ c->sign = MP_ZPOS;
+
+LBL_T:
+ mp_clear_multi (&t1, &t2, NULL);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_lcm.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_lshd.c b/crypto/userspace/libtommath/bn_mp_lshd.c
new file mode 100644
index 00000000000..f118cf1ae56
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_lshd.c
@@ -0,0 +1,67 @@
+#include <tommath.h>
+#ifdef BN_MP_LSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift left a certain amount of digits */
+int mp_lshd (mp_int * a, int b)
+{
+ int x, res;
+
+ /* if its less than zero return */
+ if (b <= 0) {
+ return MP_OKAY;
+ }
+
+ /* grow to fit the new digits */
+ if (a->alloc < a->used + b) {
+ if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ {
+ register mp_digit *top, *bottom;
+
+ /* increment the used by the shift amount then copy upwards */
+ a->used += b;
+
+ /* top */
+ top = a->dp + a->used - 1;
+
+ /* base */
+ bottom = a->dp + a->used - 1 - b;
+
+ /* much like mp_rshd this is implemented using a sliding window
+ * except the window goes the otherway around. Copying from
+ * the bottom to the top. see bn_mp_rshd.c for more info.
+ */
+ for (x = a->used - 1; x >= b; x--) {
+ *top-- = *bottom--;
+ }
+
+ /* zero the lower digits */
+ top = a->dp;
+ for (x = 0; x < b; x++) {
+ *top++ = 0;
+ }
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_lshd.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mod.c b/crypto/userspace/libtommath/bn_mp_mod.c
new file mode 100644
index 00000000000..f5cf8d09f2d
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mod.c
@@ -0,0 +1,48 @@
+#include <tommath.h>
+#ifdef BN_MP_MOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* c = a mod b, 0 <= c < b */
+int
+mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int t;
+ int res;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ if (t.sign != b->sign) {
+ res = mp_add (b, &t, c);
+ } else {
+ res = MP_OKAY;
+ mp_exch (&t, c);
+ }
+
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mod_2d.c b/crypto/userspace/libtommath/bn_mp_mod_2d.c
new file mode 100644
index 00000000000..e194a068702
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mod_2d.c
@@ -0,0 +1,55 @@
+#include <tommath.h>
+#ifdef BN_MP_MOD_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* calc a value mod 2**b */
+int
+mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+ int x, res;
+
+ /* if b is <= 0 then zero the int */
+ if (b <= 0) {
+ mp_zero (c);
+ return MP_OKAY;
+ }
+
+ /* if the modulus is larger than the value than return */
+ if (b >= (int) (a->used * DIGIT_BIT)) {
+ res = mp_copy (a, c);
+ return res;
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+
+ /* zero digits above the last digit of the modulus */
+ for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+ c->dp[x] = 0;
+ }
+ /* clear the digit that is not completely outside/inside the modulus */
+ c->dp[b / DIGIT_BIT] &=
+ (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mod_2d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mod_d.c b/crypto/userspace/libtommath/bn_mp_mod_d.c
new file mode 100644
index 00000000000..9ca37e67327
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mod_d.c
@@ -0,0 +1,27 @@
+#include <tommath.h>
+#ifdef BN_MP_MOD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+int
+mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
+{
+ return mp_div_d(a, b, NULL, c);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mod_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_montgomery_calc_normalization.c b/crypto/userspace/libtommath/bn_mp_montgomery_calc_normalization.c
new file mode 100644
index 00000000000..c669fe0ec3a
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_montgomery_calc_normalization.c
@@ -0,0 +1,59 @@
+#include <tommath.h>
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b. This saves alot of multiple precision shifting.
+ */
+int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+ int x, bits, res;
+
+ /* how many bits of last digit does b use */
+ bits = mp_count_bits (b) % DIGIT_BIT;
+
+ if (b->used > 1) {
+ if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+ return res;
+ }
+ } else {
+ mp_set(a, 1);
+ bits = 1;
+ }
+
+
+ /* now compute C = A * B mod b */
+ for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+ if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+ return res;
+ }
+ if (mp_cmp_mag (a, b) != MP_LT) {
+ if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+ return res;
+ }
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_calc_normalization.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_montgomery_reduce.c b/crypto/userspace/libtommath/bn_mp_montgomery_reduce.c
new file mode 100644
index 00000000000..b76509051be
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_montgomery_reduce.c
@@ -0,0 +1,118 @@
+#include <tommath.h>
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction */
+int
+mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int ix, res, digs;
+ mp_digit mu;
+
+ /* can the fast reduction [comba] method be used?
+ *
+ * Note that unlike in mul you're safely allowed *less*
+ * than the available columns [255 per default] since carries
+ * are fixed up in the inner loop.
+ */
+ digs = n->used * 2 + 1;
+ if ((digs < MP_WARRAY) &&
+ n->used <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_mp_montgomery_reduce (x, n, rho);
+ }
+
+ /* grow the input as required */
+ if (x->alloc < digs) {
+ if ((res = mp_grow (x, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+ x->used = digs;
+
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * rho mod b
+ *
+ * The value of rho must be precalculated via
+ * montgomery_setup() such that
+ * it equals -1/n0 mod b this allows the
+ * following inner loop to reduce the
+ * input one digit at a time
+ */
+ mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i */
+ {
+ register int iy;
+ register mp_digit *tmpn, *tmpx, u;
+ register mp_word r;
+
+ /* alias for digits of the modulus */
+ tmpn = n->dp;
+
+ /* alias for the digits of x [the input] */
+ tmpx = x->dp + ix;
+
+ /* set the carry to zero */
+ u = 0;
+
+ /* Multiply and add in place */
+ for (iy = 0; iy < n->used; iy++) {
+ /* compute product and sum */
+ r = ((mp_word)mu) * ((mp_word)*tmpn++) +
+ ((mp_word) u) + ((mp_word) * tmpx);
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+ /* fix digit */
+ *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
+ }
+ /* At this point the ix'th digit of x should be zero */
+
+
+ /* propagate carries upwards as required*/
+ while (u) {
+ *tmpx += u;
+ u = *tmpx >> DIGIT_BIT;
+ *tmpx++ &= MP_MASK;
+ }
+ }
+ }
+
+ /* at this point the n.used'th least
+ * significant digits of x are all zero
+ * which means we can shift x to the
+ * right by n.used digits and the
+ * residue is unchanged.
+ */
+
+ /* x = x/b**n.used */
+ mp_clamp(x);
+ mp_rshd (x, n->used);
+
+ /* if x >= n then x = x - n */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ return s_mp_sub (x, n, x);
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_montgomery_setup.c b/crypto/userspace/libtommath/bn_mp_montgomery_setup.c
new file mode 100644
index 00000000000..f08274936ed
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_montgomery_setup.c
@@ -0,0 +1,59 @@
+#include <tommath.h>
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* setups the montgomery reduction stuff */
+int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+ mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
+ * => 2*X*A - X*X*A*A = 1
+ * => 2*(1) - (1) = 1
+ */
+ b = n->dp[0];
+
+ if ((b & 1) == 0) {
+ return MP_VAL;
+ }
+
+ x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+ x *= 2 - b * x; /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+ x *= 2 - b * x; /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+ x *= 2 - b * x; /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+ x *= 2 - b * x; /* here x*a==1 mod 2**64 */
+#endif
+
+ /* rho = -1/m mod b */
+ *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_setup.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mul.c b/crypto/userspace/libtommath/bn_mp_mul.c
new file mode 100644
index 00000000000..8b1117a63ba
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mul.c
@@ -0,0 +1,66 @@
+#include <tommath.h>
+#ifdef BN_MP_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* high level multiplication (handles sign) */
+int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res, neg;
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+ /* use Toom-Cook? */
+#ifdef BN_MP_TOOM_MUL_C
+ if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
+ res = mp_toom_mul(a, b, c);
+ } else
+#endif
+#ifdef BN_MP_KARATSUBA_MUL_C
+ /* use Karatsuba? */
+ if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
+ res = mp_karatsuba_mul (a, b, c);
+ } else
+#endif
+ {
+ /* can we use the fast multiplier?
+ *
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
+ * digits won't affect carry propagation
+ */
+ int digs = a->used + b->used + 1;
+
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+ if ((digs < MP_WARRAY) &&
+ MIN(a->used, b->used) <=
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ res = fast_s_mp_mul_digs (a, b, c, digs);
+ } else
+#endif
+#ifdef BN_S_MP_MUL_DIGS_C
+ res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
+#else
+ res = MP_VAL;
+#endif
+
+ }
+ c->sign = (c->used > 0) ? neg : MP_ZPOS;
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mul_2.c b/crypto/userspace/libtommath/bn_mp_mul_2.c
new file mode 100644
index 00000000000..02455fc35d4
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mul_2.c
@@ -0,0 +1,82 @@
+#include <tommath.h>
+#ifdef BN_MP_MUL_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = a*2 */
+int mp_mul_2(mp_int * a, mp_int * b)
+{
+ int x, res, oldused;
+
+ /* grow to accomodate result */
+ if (b->alloc < a->used + 1) {
+ if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ {
+ register mp_digit r, rr, *tmpa, *tmpb;
+
+ /* alias for source */
+ tmpa = a->dp;
+
+ /* alias for dest */
+ tmpb = b->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < a->used; x++) {
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
+ */
+ rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+
+ /* now shift up this digit, add in the carry [from the previous] */
+ *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
+ */
+ r = rr;
+ }
+
+ /* new leading digit? */
+ if (r != 0) {
+ /* add a MSB which is always 1 at this point */
+ *tmpb = 1;
+ ++(b->used);
+ }
+
+ /* now zero any excess digits on the destination
+ * that we didn't write to
+ */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mul_2d.c b/crypto/userspace/libtommath/bn_mp_mul_2d.c
new file mode 100644
index 00000000000..efeff2e7518
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mul_2d.c
@@ -0,0 +1,85 @@
+#include <tommath.h>
+#ifdef BN_MP_MUL_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift left by a certain bit count */
+int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+ mp_digit d;
+ int res;
+
+ /* copy */
+ if (a != c) {
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+ if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= (int)DIGIT_BIT) {
+ if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ d = (mp_digit) (b % DIGIT_BIT);
+ if (d != 0) {
+ register mp_digit *tmpc, shift, mask, r, rr;
+ register int x;
+
+ /* bitmask for carries */
+ mask = (((mp_digit)1) << d) - 1;
+
+ /* shift for msbs */
+ shift = DIGIT_BIT - d;
+
+ /* alias */
+ tmpc = c->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < c->used; x++) {
+ /* get the higher bits of the current word */
+ rr = (*tmpc >> shift) & mask;
+
+ /* shift the current word and OR in the carry */
+ *tmpc = ((*tmpc << d) | r) & MP_MASK;
+ ++tmpc;
+
+ /* set the carry to the carry bits of the current word */
+ r = rr;
+ }
+
+ /* set final carry */
+ if (r != 0) {
+ c->dp[(c->used)++] = r;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mul_d.c b/crypto/userspace/libtommath/bn_mp_mul_d.c
new file mode 100644
index 00000000000..00f9a899ef4
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mul_d.c
@@ -0,0 +1,79 @@
+#include <tommath.h>
+#ifdef BN_MP_MUL_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiply by a digit */
+int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit u, *tmpa, *tmpc;
+ mp_word r;
+ int ix, res, olduse;
+
+ /* make sure c is big enough to hold a*b */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* get the original destinations used count */
+ olduse = c->used;
+
+ /* set the sign */
+ c->sign = a->sign;
+
+ /* alias for a->dp [source] */
+ tmpa = a->dp;
+
+ /* alias for c->dp [dest] */
+ tmpc = c->dp;
+
+ /* zero carry */
+ u = 0;
+
+ /* compute columns */
+ for (ix = 0; ix < a->used; ix++) {
+ /* compute product and carry sum for this term */
+ r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+ /* mask off higher bits to get a single digit */
+ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* send carry into next iteration */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+
+ /* store final carry [if any] and increment ix offset */
+ *tmpc++ = u;
+ ++ix;
+
+ /* now zero digits above the top */
+ while (ix++ < olduse) {
+ *tmpc++ = 0;
+ }
+
+ /* set used count */
+ c->used = a->used + 1;
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mul_d.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_mulmod.c b/crypto/userspace/libtommath/bn_mp_mulmod.c
new file mode 100644
index 00000000000..003ceb9b97e
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_mulmod.c
@@ -0,0 +1,40 @@
+#include <tommath.h>
+#ifdef BN_MP_MULMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* d = a * b (mod c) */
+int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_mulmod.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_n_root.c b/crypto/userspace/libtommath/bn_mp_n_root.c
new file mode 100644
index 00000000000..0e7bedca72c
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_n_root.c
@@ -0,0 +1,132 @@
+#include <tommath.h>
+#ifdef BN_MP_N_ROOT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* find the n'th root of an integer
+ *
+ * Result found such that (c)**b <= a and (c+1)**b > a
+ *
+ * This algorithm uses Newton's approximation
+ * x[i+1] = x[i] - f(x[i])/f'(x[i])
+ * which will find the root in log(N) time where
+ * each step involves a fair bit. This is not meant to
+ * find huge roots [square and cube, etc].
+ */
+int mp_n_root (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_int t1, t2, t3;
+ int res, neg;
+
+ /* input must be positive if b is even */
+ if ((b & 1) == 0 && a->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ if ((res = mp_init (&t1)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_init (&t2)) != MP_OKAY) {
+ goto LBL_T1;
+ }
+
+ if ((res = mp_init (&t3)) != MP_OKAY) {
+ goto LBL_T2;
+ }
+
+ /* if a is negative fudge the sign but keep track */
+ neg = a->sign;
+ a->sign = MP_ZPOS;
+
+ /* t2 = 2 */
+ mp_set (&t2, 2);
+
+ do {
+ /* t1 = t2 */
+ if ((res = mp_copy (&t2, &t1)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
+
+ /* t3 = t1**(b-1) */
+ if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* numerator */
+ /* t2 = t1**b */
+ if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* t2 = t1**b - a */
+ if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* denominator */
+ /* t3 = t1**(b-1) * b */
+ if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ /* t3 = (t1**b - a)/(b * t1**(b-1)) */
+ if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+ } while (mp_cmp (&t1, &t2) != MP_EQ);
+
+ /* result can be off by a few so check */
+ for (;;) {
+ if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+
+ if (mp_cmp (&t2, a) == MP_GT) {
+ if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) {
+ goto LBL_T3;
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* reset the sign of a first */
+ a->sign = neg;
+
+ /* set the result */
+ mp_exch (&t1, c);
+
+ /* set the sign of the result */
+ c->sign = neg;
+
+ res = MP_OKAY;
+
+LBL_T3:mp_clear (&t3);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_n_root.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_neg.c b/crypto/userspace/libtommath/bn_mp_neg.c
new file mode 100644
index 00000000000..a7d035ab6dd
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_neg.c
@@ -0,0 +1,40 @@
+#include <tommath.h>
+#ifdef BN_MP_NEG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* b = -a */
+int mp_neg (mp_int * a, mp_int * b)
+{
+ int res;
+ if (a != b) {
+ if ((res = mp_copy (a, b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ if (mp_iszero(b) != MP_YES) {
+ b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ } else {
+ b->sign = MP_ZPOS;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_neg.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_prime_is_divisible.c b/crypto/userspace/libtommath/bn_mp_prime_is_divisible.c
new file mode 100644
index 00000000000..8e7871c2c65
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_prime_is_divisible.c
@@ -0,0 +1,50 @@
+#include <tommath.h>
+#ifdef BN_MP_PRIME_IS_DIVISIBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if an integers is divisible by one
+ * of the first PRIME_SIZE primes or not
+ *
+ * sets result to 0 if not, 1 if yes
+ */
+int mp_prime_is_divisible (mp_int * a, int *result)
+{
+ int err, ix;
+ mp_digit res;
+
+ /* default to not */
+ *result = MP_NO;
+
+ for (ix = 0; ix < PRIME_SIZE; ix++) {
+ /* what is a mod LBL_prime_tab[ix] */
+ if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* is the residue zero? */
+ if (res == 0) {
+ *result = MP_YES;
+ return MP_OKAY;
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_divisible.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_prime_is_prime.c b/crypto/userspace/libtommath/bn_mp_prime_is_prime.c
new file mode 100644
index 00000000000..c316d621090
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_prime_is_prime.c
@@ -0,0 +1,83 @@
+#include <tommath.h>
+#ifdef BN_MP_PRIME_IS_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* performs a variable number of rounds of Miller-Rabin
+ *
+ * Probability of error after t rounds is no more than
+
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime (mp_int * a, int t, int *result)
+{
+ mp_int b;
+ int ix, err, res;
+
+ /* default to no */
+ *result = MP_NO;
+
+ /* valid value of t? */
+ if (t <= 0 || t > PRIME_SIZE) {
+ return MP_VAL;
+ }
+
+ /* is the input equal to one of the primes in the table? */
+ for (ix = 0; ix < PRIME_SIZE; ix++) {
+ if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
+ *result = 1;
+ return MP_OKAY;
+ }
+ }
+
+ /* first perform trial division */
+ if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* return if it was trivially divisible */
+ if (res == MP_YES) {
+ return MP_OKAY;
+ }
+
+ /* now perform the miller-rabin rounds */
+ if ((err = mp_init (&b)) != MP_OKAY) {
+ return err;
+ }
+
+ for (ix = 0; ix < t; ix++) {
+ /* set the prime */
+ mp_set (&b, ltm_prime_tab[ix]);
+
+ if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+ }
+
+ /* passed the test */
+ *result = MP_YES;
+LBL_B:mp_clear (&b);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_prime.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_prime_miller_rabin.c b/crypto/userspace/libtommath/bn_mp_prime_miller_rabin.c
new file mode 100644
index 00000000000..ddf03582ac4
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_prime_miller_rabin.c
@@ -0,0 +1,103 @@
+#include <tommath.h>
+#ifdef BN_MP_PRIME_MILLER_RABIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Miller-Rabin test of "a" to the base of "b" as described in
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often
+ * very much lower.
+ */
+int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result)
+{
+ mp_int n1, y, r;
+ int s, j, err;
+
+ /* default */
+ *result = MP_NO;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* get n1 = a - 1 */
+ if ((err = mp_init_copy (&n1, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) {
+ goto LBL_N1;
+ }
+
+ /* set 2**s * r = n1 */
+ if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) {
+ goto LBL_N1;
+ }
+
+ /* count the number of least significant bits
+ * which are zero
+ */
+ s = mp_cnt_lsb(&r);
+
+ /* now divide n - 1 by 2**s */
+ if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) {
+ goto LBL_R;
+ }
+
+ /* compute y = b**r mod a */
+ if ((err = mp_init (&y)) != MP_OKAY) {
+ goto LBL_R;
+ }
+ if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if y != 1 and y != n1 do */
+ if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) {
+ j = 1;
+ /* while j <= s-1 and y != n1 */
+ while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) {
+ if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if y == 1 then composite */
+ if (mp_cmp_d (&y, 1) == MP_EQ) {
+ goto LBL_Y;
+ }
+
+ ++j;
+ }
+
+ /* if y != n1 then composite */
+ if (mp_cmp (&y, &n1) != MP_EQ) {
+ goto LBL_Y;
+ }
+ }
+
+ /* probably prime now */
+ *result = MP_YES;
+LBL_Y:mp_clear (&y);
+LBL_R:mp_clear (&r);
+LBL_N1:mp_clear (&n1);
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_miller_rabin.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_prime_next_prime.c b/crypto/userspace/libtommath/bn_mp_prime_next_prime.c
new file mode 100644
index 00000000000..bc31cc72086
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_prime_next_prime.c
@@ -0,0 +1,170 @@
+#include <tommath.h>
+#ifdef BN_MP_PRIME_NEXT_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+int mp_prime_next_prime(mp_int *a, int t, int bbs_style)
+{
+ int err, res, x, y;
+ mp_digit res_tab[PRIME_SIZE], step, kstep;
+ mp_int b;
+
+ /* ensure t is valid */
+ if (t <= 0 || t > PRIME_SIZE) {
+ return MP_VAL;
+ }
+
+ /* force positive */
+ a->sign = MP_ZPOS;
+
+ /* simple algo if a is less than the largest prime in the table */
+ if (mp_cmp_d(a, ltm_prime_tab[PRIME_SIZE-1]) == MP_LT) {
+ /* find which prime it is bigger than */
+ for (x = PRIME_SIZE - 2; x >= 0; x--) {
+ if (mp_cmp_d(a, ltm_prime_tab[x]) != MP_LT) {
+ if (bbs_style == 1) {
+ /* ok we found a prime smaller or
+ * equal [so the next is larger]
+ *
+ * however, the prime must be
+ * congruent to 3 mod 4
+ */
+ if ((ltm_prime_tab[x + 1] & 3) != 3) {
+ /* scan upwards for a prime congruent to 3 mod 4 */
+ for (y = x + 1; y < PRIME_SIZE; y++) {
+ if ((ltm_prime_tab[y] & 3) == 3) {
+ mp_set(a, ltm_prime_tab[y]);
+ return MP_OKAY;
+ }
+ }
+ }
+ } else {
+ mp_set(a, ltm_prime_tab[x + 1]);
+ return MP_OKAY;
+ }
+ }
+ }
+ /* at this point a maybe 1 */
+ if (mp_cmp_d(a, 1) == MP_EQ) {
+ mp_set(a, 2);
+ return MP_OKAY;
+ }
+ /* fall through to the sieve */
+ }
+
+ /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */
+ if (bbs_style == 1) {
+ kstep = 4;
+ } else {
+ kstep = 2;
+ }
+
+ /* at this point we will use a combination of a sieve and Miller-Rabin */
+
+ if (bbs_style == 1) {
+ /* if a mod 4 != 3 subtract the correct value to make it so */
+ if ((a->dp[0] & 3) != 3) {
+ if ((err = mp_sub_d(a, (a->dp[0] & 3) + 1, a)) != MP_OKAY) { return err; };
+ }
+ } else {
+ if (mp_iseven(a) == 1) {
+ /* force odd */
+ if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ }
+
+ /* generate the restable */
+ for (x = 1; x < PRIME_SIZE; x++) {
+ if ((err = mp_mod_d(a, ltm_prime_tab[x], res_tab + x)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* init temp used for Miller-Rabin Testing */
+ if ((err = mp_init(&b)) != MP_OKAY) {
+ return err;
+ }
+
+ for (;;) {
+ /* skip to the next non-trivially divisible candidate */
+ step = 0;
+ do {
+ /* y == 1 if any residue was zero [e.g. cannot be prime] */
+ y = 0;
+
+ /* increase step to next candidate */
+ step += kstep;
+
+ /* compute the new residue without using division */
+ for (x = 1; x < PRIME_SIZE; x++) {
+ /* add the step to each residue */
+ res_tab[x] += kstep;
+
+ /* subtract the modulus [instead of using division] */
+ if (res_tab[x] >= ltm_prime_tab[x]) {
+ res_tab[x] -= ltm_prime_tab[x];
+ }
+
+ /* set flag if zero */
+ if (res_tab[x] == 0) {
+ y = 1;
+ }
+ }
+ } while (y == 1 && step < ((((mp_digit)1)<<DIGIT_BIT) - kstep));
+
+ /* add the step */
+ if ((err = mp_add_d(a, step, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* if didn't pass sieve and step == MAX then skip test */
+ if (y == 1 && step >= ((((mp_digit)1)<<DIGIT_BIT) - kstep)) {
+ continue;
+ }
+
+ /* is this prime? */
+ for (x = 0; x < t; x++) {
+ mp_set(&b, ltm_prime_tab[x]);
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (res == MP_NO) {
+ break;
+ }
+ }
+
+ if (res == MP_YES) {
+ break;
+ }
+ }
+
+ err = MP_OKAY;
+LBL_ERR:
+ mp_clear(&b);
+ return err;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_next_prime.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_prime_rabin_miller_trials.c b/crypto/userspace/libtommath/bn_mp_prime_rabin_miller_trials.c
new file mode 100644
index 00000000000..248c2fd2e6e
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_prime_rabin_miller_trials.c
@@ -0,0 +1,52 @@
+#include <tommath.h>
+#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+
+static const struct {
+ int k, t;
+} sizes[] = {
+{ 128, 28 },
+{ 256, 16 },
+{ 384, 10 },
+{ 512, 7 },
+{ 640, 6 },
+{ 768, 5 },
+{ 896, 4 },
+{ 1024, 4 }
+};
+
+/* returns # of RM trials required for a given bit size */
+int mp_prime_rabin_miller_trials(int size)
+{
+ int x;
+
+ for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) {
+ if (sizes[x].k == size) {
+ return sizes[x].t;
+ } else if (sizes[x].k > size) {
+ return (x == 0) ? sizes[0].t : sizes[x - 1].t;
+ }
+ }
+ return sizes[x-1].t + 1;
+}
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_rabin_miller_trials.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_prime_random_ex.c b/crypto/userspace/libtommath/bn_mp_prime_random_ex.c
new file mode 100644
index 00000000000..07aae4b072e
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_prime_random_ex.c
@@ -0,0 +1,125 @@
+#include <tommath.h>
+#ifdef BN_MP_PRIME_RANDOM_EX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * LTM_PRIME_BBS - make prime congruent to 3 mod 4
+ * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
+ * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero
+ * LTM_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+
+/* This is possibly the mother of all prime generation functions, muahahahahaha! */
+int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat)
+{
+ unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb;
+ int res, err, bsize, maskOR_msb_offset;
+
+ /* sanity check the input */
+ if (size <= 1 || t <= 0) {
+ return MP_VAL;
+ }
+
+ /* LTM_PRIME_SAFE implies LTM_PRIME_BBS */
+ if (flags & LTM_PRIME_SAFE) {
+ flags |= LTM_PRIME_BBS;
+ }
+
+ /* calc the byte size */
+ bsize = (size>>3) + ((size&7)?1:0);
+
+ /* we need a buffer of bsize bytes */
+ tmp = OPT_CAST(unsigned char) XMALLOC(bsize);
+ if (tmp == NULL) {
+ return MP_MEM;
+ }
+
+ /* calc the maskAND value for the MSbyte*/
+ maskAND = ((size&7) == 0) ? 0xFF : (0xFF >> (8 - (size & 7)));
+
+ /* calc the maskOR_msb */
+ maskOR_msb = 0;
+ maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0;
+ if (flags & LTM_PRIME_2MSB_ON) {
+ maskOR_msb |= 0x80 >> ((9 - size) & 7);
+ }
+
+ /* get the maskOR_lsb */
+ maskOR_lsb = 1;
+ if (flags & LTM_PRIME_BBS) {
+ maskOR_lsb |= 3;
+ }
+
+ do {
+ /* read the bytes */
+ if (cb(tmp, bsize, dat) != bsize) {
+ err = MP_VAL;
+ goto error;
+ }
+
+ /* work over the MSbyte */
+ tmp[0] &= maskAND;
+ tmp[0] |= 1 << ((size - 1) & 7);
+
+ /* mix in the maskORs */
+ tmp[maskOR_msb_offset] |= maskOR_msb;
+ tmp[bsize-1] |= maskOR_lsb;
+
+ /* read it in */
+ if ((err = mp_read_unsigned_bin(a, tmp, bsize)) != MP_OKAY) { goto error; }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; }
+ if (res == MP_NO) {
+ continue;
+ }
+
+ if (flags & LTM_PRIME_SAFE) {
+ /* see if (a-1)/2 is prime */
+ if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { goto error; }
+ if ((err = mp_div_2(a, a)) != MP_OKAY) { goto error; }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; }
+ }
+ } while (res == MP_NO);
+
+ if (flags & LTM_PRIME_SAFE) {
+ /* restore a to the original value */
+ if ((err = mp_mul_2(a, a)) != MP_OKAY) { goto error; }
+ if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { goto error; }
+ }
+
+ err = MP_OKAY;
+error:
+ XFREE(tmp);
+ return err;
+}
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_prime_random_ex.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_rand.c b/crypto/userspace/libtommath/bn_mp_rand.c
new file mode 100644
index 00000000000..af66a67eea1
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_rand.c
@@ -0,0 +1,55 @@
+#include <tommath.h>
+#ifdef BN_MP_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* makes a pseudo-random int of a given size */
+int
+mp_rand (mp_int * a, int digits)
+{
+ int res;
+ mp_digit d;
+
+ mp_zero (a);
+ if (digits <= 0) {
+ return MP_OKAY;
+ }
+
+ /* first place a random non-zero digit */
+ do {
+ d = ((mp_digit) abs (rand ())) & MP_MASK;
+ } while (d == 0);
+
+ if ((res = mp_add_d (a, d, a)) != MP_OKAY) {
+ return res;
+ }
+
+ while (--digits > 0) {
+ if ((res = mp_lshd (a, 1)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_rand.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_read_signed_bin.c b/crypto/userspace/libtommath/bn_mp_read_signed_bin.c
new file mode 100644
index 00000000000..8da651ce30f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_read_signed_bin.c
@@ -0,0 +1,41 @@
+#include <tommath.h>
+#ifdef BN_MP_READ_SIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* read signed bin, big endian, first byte is 0==positive or 1==negative */
+int mp_read_signed_bin (mp_int * a, const unsigned char *b, int c)
+{
+ int res;
+
+ /* read magnitude */
+ if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* first byte is 0 for positive, non-zero for negative */
+ if (b[0] == 0) {
+ a->sign = MP_ZPOS;
+ } else {
+ a->sign = MP_NEG;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_read_signed_bin.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_read_unsigned_bin.c b/crypto/userspace/libtommath/bn_mp_read_unsigned_bin.c
new file mode 100644
index 00000000000..1ebba13a02c
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_read_unsigned_bin.c
@@ -0,0 +1,55 @@
+#include <tommath.h>
+#ifdef BN_MP_READ_UNSIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+ int res;
+
+ /* make sure there are at least two digits */
+ if (a->alloc < 2) {
+ if ((res = mp_grow(a, 2)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* zero the int */
+ mp_zero (a);
+
+ /* read the bytes in */
+ while (c-- > 0) {
+ if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+ return res;
+ }
+
+#ifndef MP_8BIT
+ a->dp[0] |= *b++;
+ a->used += 1;
+#else
+ a->dp[0] = (*b & MP_MASK);
+ a->dp[1] |= ((*b++ >> 7U) & 1);
+ a->used += 2;
+#endif
+ }
+ mp_clamp (a);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_read_unsigned_bin.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce.c b/crypto/userspace/libtommath/bn_mp_reduce.c
new file mode 100644
index 00000000000..21d07309058
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce.c
@@ -0,0 +1,100 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
+{
+ mp_int q;
+ int res, um = m->used;
+
+ /* q = x */
+ if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
+ return res;
+ }
+
+ /* q1 = x / b**(k-1) */
+ mp_rshd (&q, um - 1);
+
+ /* according to HAC this optimization is ok */
+ if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
+ if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ } else {
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+ if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+ if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+#else
+ {
+ res = MP_VAL;
+ goto CLEANUP;
+ }
+#endif
+ }
+
+ /* q3 = q2 / b**(k+1) */
+ mp_rshd (&q, um + 1);
+
+ /* x = x mod b**(k+1), quick (no division) */
+ if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* q = q * m mod b**(k+1), quick (no division) */
+ if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* x = x - q */
+ if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* If x < 0, add b**(k+1) to it */
+ if (mp_cmp_d (x, 0) == MP_LT) {
+ mp_set (&q, 1);
+ if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
+ goto CLEANUP;
+ if ((res = mp_add (x, &q, x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ /* Back off if it's too big */
+ while (mp_cmp (x, m) != MP_LT) {
+ if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ }
+
+CLEANUP:
+ mp_clear (&q);
+
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_2k.c b/crypto/userspace/libtommath/bn_mp_reduce_2k.c
new file mode 100644
index 00000000000..d9620c221c2
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_2k.c
@@ -0,0 +1,61 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduces a modulo n where n is of the form 2**p - d */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
+{
+ mp_int q;
+ int p, res;
+
+ if ((res = mp_init(&q)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (d != 1) {
+ /* q = q * d */
+ if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) {
+ goto ERR;
+ }
+ }
+
+ /* a = a + q */
+ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ s_mp_sub(a, n, a);
+ goto top;
+ }
+
+ERR:
+ mp_clear(&q);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_2k_l.c b/crypto/userspace/libtommath/bn_mp_reduce_2k_l.c
new file mode 100644
index 00000000000..f06103d6a67
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_2k_l.c
@@ -0,0 +1,62 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reduces a modulo n where n is of the form 2**p - d
+ This differs from reduce_2k since "d" can be larger
+ than a single digit.
+*/
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
+{
+ mp_int q;
+ int p, res;
+
+ if ((res = mp_init(&q)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* q = q * d */
+ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* a = a + q */
+ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ s_mp_sub(a, n, a);
+ goto top;
+ }
+
+ERR:
+ mp_clear(&q);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_l.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_2k_setup.c b/crypto/userspace/libtommath/bn_mp_reduce_2k_setup.c
new file mode 100644
index 00000000000..a80e7a22f22
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_2k_setup.c
@@ -0,0 +1,47 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_2K_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines the setup value */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
+{
+ int res, p;
+ mp_int tmp;
+
+ if ((res = mp_init(&tmp)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(a);
+ if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return res;
+ }
+
+ if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return res;
+ }
+
+ *d = tmp.dp[0];
+ mp_clear(&tmp);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_2k_setup_l.c b/crypto/userspace/libtommath/bn_mp_reduce_2k_setup_l.c
new file mode 100644
index 00000000000..7cf002e8885
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_2k_setup_l.c
@@ -0,0 +1,44 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_2K_SETUP_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines the setup value */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
+{
+ int res;
+ mp_int tmp;
+
+ if ((res = mp_init(&tmp)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear(&tmp);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup_l.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_is_2k.c b/crypto/userspace/libtommath/bn_mp_reduce_is_2k.c
new file mode 100644
index 00000000000..7308be73e2b
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_is_2k.c
@@ -0,0 +1,52 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_IS_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if mp_reduce_2k can be used */
+int mp_reduce_is_2k(mp_int *a)
+{
+ int ix, iy, iw;
+ mp_digit iz;
+
+ if (a->used == 0) {
+ return MP_NO;
+ } else if (a->used == 1) {
+ return MP_YES;
+ } else if (a->used > 1) {
+ iy = mp_count_bits(a);
+ iz = 1;
+ iw = 1;
+
+ /* Test every bit from the second digit up, must be 1 */
+ for (ix = DIGIT_BIT; ix < iy; ix++) {
+ if ((a->dp[iw] & iz) == 0) {
+ return MP_NO;
+ }
+ iz <<= 1;
+ if (iz > (mp_digit)MP_MASK) {
+ ++iw;
+ iz = 1;
+ }
+ }
+ }
+ return MP_YES;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_is_2k_l.c b/crypto/userspace/libtommath/bn_mp_reduce_is_2k_l.c
new file mode 100644
index 00000000000..14a4d218461
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_is_2k_l.c
@@ -0,0 +1,44 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_IS_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* determines if reduce_2k_l can be used */
+int mp_reduce_is_2k_l(mp_int *a)
+{
+ int ix, iy;
+
+ if (a->used == 0) {
+ return MP_NO;
+ } else if (a->used == 1) {
+ return MP_YES;
+ } else if (a->used > 1) {
+ /* if more than half of the digits are -1 we're sold */
+ for (iy = ix = 0; ix < a->used; ix++) {
+ if (a->dp[ix] == MP_MASK) {
+ ++iy;
+ }
+ }
+ return (iy >= (a->used/2)) ? MP_YES : MP_NO;
+
+ }
+ return MP_NO;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k_l.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_reduce_setup.c b/crypto/userspace/libtommath/bn_mp_reduce_setup.c
new file mode 100644
index 00000000000..370f20bb17c
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_reduce_setup.c
@@ -0,0 +1,34 @@
+#include <tommath.h>
+#ifdef BN_MP_REDUCE_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+int mp_reduce_setup (mp_int * a, mp_int * b)
+{
+ int res;
+
+ if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ return mp_div (a, b, a, NULL);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_setup.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_rshd.c b/crypto/userspace/libtommath/bn_mp_rshd.c
new file mode 100644
index 00000000000..2a693c5a5b3
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_rshd.c
@@ -0,0 +1,72 @@
+#include <tommath.h>
+#ifdef BN_MP_RSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shift right a certain amount of digits */
+void mp_rshd (mp_int * a, int b)
+{
+ int x;
+
+ /* if b <= 0 then ignore it */
+ if (b <= 0) {
+ return;
+ }
+
+ /* if b > used then simply zero it and return */
+ if (a->used <= b) {
+ mp_zero (a);
+ return;
+ }
+
+ {
+ register mp_digit *bottom, *top;
+
+ /* shift the digits down */
+
+ /* bottom */
+ bottom = a->dp;
+
+ /* top [offset into digits] */
+ top = a->dp + b;
+
+ /* this is implemented as a sliding window where
+ * the window is b-digits long and digits from
+ * the top of the window are copied to the bottom
+ *
+ * e.g.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+ for (x = 0; x < (a->used - b); x++) {
+ *bottom++ = *top++;
+ }
+
+ /* zero the top digits */
+ for (; x < a->used; x++) {
+ *bottom++ = 0;
+ }
+ }
+
+ /* remove excess digits */
+ a->used -= b;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_rshd.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_set.c b/crypto/userspace/libtommath/bn_mp_set.c
new file mode 100644
index 00000000000..174adcbc6d6
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_set.c
@@ -0,0 +1,29 @@
+#include <tommath.h>
+#ifdef BN_MP_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* set to a digit */
+void mp_set (mp_int * a, mp_digit b)
+{
+ mp_zero (a);
+ a->dp[0] = b & MP_MASK;
+ a->used = (a->dp[0] != 0) ? 1 : 0;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_set.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_set_int.c b/crypto/userspace/libtommath/bn_mp_set_int.c
new file mode 100644
index 00000000000..cf10ea1a448
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_set_int.c
@@ -0,0 +1,48 @@
+#include <tommath.h>
+#ifdef BN_MP_SET_INT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* set a 32-bit const */
+int mp_set_int (mp_int * a, unsigned long b)
+{
+ int x, res;
+
+ mp_zero (a);
+
+ /* set four bits at a time */
+ for (x = 0; x < 8; x++) {
+ /* shift the number up four bits */
+ if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) {
+ return res;
+ }
+
+ /* OR in the top four bits of the source */
+ a->dp[0] |= (b >> 28) & 15;
+
+ /* shift the source up to the next four bits */
+ b <<= 4;
+
+ /* ensure that digits are not clamped off */
+ a->used += 1;
+ }
+ mp_clamp (a);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_set_int.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_shrink.c b/crypto/userspace/libtommath/bn_mp_shrink.c
new file mode 100644
index 00000000000..4b8c5ef11ad
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_shrink.c
@@ -0,0 +1,35 @@
+#include <tommath.h>
+#ifdef BN_MP_SHRINK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* shrink a bignum */
+int mp_shrink (mp_int * a)
+{
+ mp_digit *tmp;
+ if (a->alloc != a->used && a->used > 0) {
+ if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) {
+ return MP_MEM;
+ }
+ a->dp = tmp;
+ a->alloc = a->used;
+ }
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_shrink.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_signed_bin_size.c b/crypto/userspace/libtommath/bn_mp_signed_bin_size.c
new file mode 100644
index 00000000000..6739d19e2bc
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_signed_bin_size.c
@@ -0,0 +1,27 @@
+#include <tommath.h>
+#ifdef BN_MP_SIGNED_BIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* get the size for an signed equivalent */
+int mp_signed_bin_size (mp_int * a)
+{
+ return 1 + mp_unsigned_bin_size (a);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_signed_bin_size.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_sqr.c b/crypto/userspace/libtommath/bn_mp_sqr.c
new file mode 100644
index 00000000000..868ccbbaef5
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_sqr.c
@@ -0,0 +1,58 @@
+#include <tommath.h>
+#ifdef BN_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* computes b = a*a */
+int
+mp_sqr (mp_int * a, mp_int * b)
+{
+ int res;
+
+#ifdef BN_MP_TOOM_SQR_C
+ /* use Toom-Cook? */
+ if (a->used >= TOOM_SQR_CUTOFF) {
+ res = mp_toom_sqr(a, b);
+ /* Karatsuba? */
+ } else
+#endif
+#ifdef BN_MP_KARATSUBA_SQR_C
+if (a->used >= KARATSUBA_SQR_CUTOFF) {
+ res = mp_karatsuba_sqr (a, b);
+ } else
+#endif
+ {
+#ifdef BN_FAST_S_MP_SQR_C
+ /* can we use the fast comba multiplier? */
+ if ((a->used * 2 + 1) < MP_WARRAY &&
+ a->used <
+ (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+ res = fast_s_mp_sqr (a, b);
+ } else
+#endif
+#ifdef BN_S_MP_SQR_C
+ res = s_mp_sqr (a, b);
+#else
+ res = MP_VAL;
+#endif
+ }
+ b->sign = MP_ZPOS;
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_sqrmod.c b/crypto/userspace/libtommath/bn_mp_sqrmod.c
new file mode 100644
index 00000000000..161cbbb30dd
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_sqrmod.c
@@ -0,0 +1,41 @@
+#include <tommath.h>
+#ifdef BN_MP_SQRMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* c = a * a (mod b) */
+int
+mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_sqr (a, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, b, c);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sqrmod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_sub.c b/crypto/userspace/libtommath/bn_mp_sub.c
new file mode 100644
index 00000000000..f5015cce45e
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_sub.c
@@ -0,0 +1,59 @@
+#include <tommath.h>
+#ifdef BN_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* high level subtraction (handles signs) */
+int
+mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int sa, sb, res;
+
+ sa = a->sign;
+ sb = b->sign;
+
+ if (sa != sb) {
+ /* subtract a negative from a positive, OR */
+ /* subtract a positive from a negative. */
+ /* In either case, ADD their magnitudes, */
+ /* and use the sign of the first number. */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+ /* subtract a positive from a positive, OR */
+ /* subtract a negative from a negative. */
+ /* First, take the difference between their */
+ /* magnitudes, then... */
+ if (mp_cmp_mag (a, b) != MP_LT) {
+ /* Copy the sign from the first */
+ c->sign = sa;
+ /* The first has a larger or equal magnitude */
+ res = s_mp_sub (a, b, c);
+ } else {
+ /* The result has the *opposite* sign from */
+ /* the first number. */
+ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ /* The second has a larger magnitude */
+ res = s_mp_sub (b, a, c);
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sub.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_sub_d.c b/crypto/userspace/libtommath/bn_mp_sub_d.c
new file mode 100644
index 00000000000..06cdca636d9
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_sub_d.c
@@ -0,0 +1,93 @@
+#include <tommath.h>
+#ifdef BN_MP_SUB_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* single digit subtraction */
+int
+mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit *tmpa, *tmpc, mu;
+ int res, ix, oldused;
+
+ /* grow c as required */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* if a is negative just do an unsigned
+ * addition [with fudged signs]
+ */
+ if (a->sign == MP_NEG) {
+ a->sign = MP_ZPOS;
+ res = mp_add_d(a, b, c);
+ a->sign = c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return res;
+ }
+
+ /* setup regs */
+ oldused = c->used;
+ tmpa = a->dp;
+ tmpc = c->dp;
+
+ /* if a <= b simply fix the single digit */
+ if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
+ if (a->used == 1) {
+ *tmpc++ = b - *tmpa;
+ } else {
+ *tmpc++ = b;
+ }
+ ix = 1;
+
+ /* negative/1digit */
+ c->sign = MP_NEG;
+ c->used = 1;
+ } else {
+ /* positive/size */
+ c->sign = MP_ZPOS;
+ c->used = a->used;
+
+ /* subtract first digit */
+ *tmpc = *tmpa++ - b;
+ mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+ *tmpc++ &= MP_MASK;
+
+ /* handle rest of the digits */
+ for (ix = 1; ix < a->used; ix++) {
+ *tmpc = *tmpa++ - mu;
+ mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* zero excess digits */
+ while (ix++ < oldused) {
+ *tmpc++ = 0;
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_sub_d.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_submod.c b/crypto/userspace/libtommath/bn_mp_submod.c
new file mode 100644
index 00000000000..869e23cded5
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_submod.c
@@ -0,0 +1,42 @@
+#include <tommath.h>
+#ifdef BN_MP_SUBMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* d = a - b (mod c) */
+int
+mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_sub (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_submod.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_to_signed_bin.c b/crypto/userspace/libtommath/bn_mp_to_signed_bin.c
new file mode 100644
index 00000000000..9df83ca5266
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_to_signed_bin.c
@@ -0,0 +1,33 @@
+#include <tommath.h>
+#ifdef BN_MP_TO_SIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in signed [big endian] format */
+int mp_to_signed_bin (mp_int * a, unsigned char *b)
+{
+ int res;
+
+ if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) {
+ return res;
+ }
+ b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_to_signed_bin_n.c b/crypto/userspace/libtommath/bn_mp_to_signed_bin_n.c
new file mode 100644
index 00000000000..677f827d4f4
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_to_signed_bin_n.c
@@ -0,0 +1,31 @@
+#include <tommath.h>
+#ifdef BN_MP_TO_SIGNED_BIN_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in signed [big endian] format */
+int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen)
+{
+ if (*outlen < (unsigned long)mp_signed_bin_size(a)) {
+ return MP_VAL;
+ }
+ *outlen = mp_signed_bin_size(a);
+ return mp_to_signed_bin(a, b);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin_n.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_to_unsigned_bin.c b/crypto/userspace/libtommath/bn_mp_to_unsigned_bin.c
new file mode 100644
index 00000000000..c137f104ac7
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_to_unsigned_bin.c
@@ -0,0 +1,48 @@
+#include <tommath.h>
+#ifdef BN_MP_TO_UNSIGNED_BIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+ int x, res;
+ mp_int t;
+
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ x = 0;
+ while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+ b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+ b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+ if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+ bn_reverse (b, x);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_to_unsigned_bin_n.c b/crypto/userspace/libtommath/bn_mp_to_unsigned_bin_n.c
new file mode 100644
index 00000000000..0dc00c623d3
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_to_unsigned_bin_n.c
@@ -0,0 +1,31 @@
+#include <tommath.h>
+#ifdef BN_MP_TO_UNSIGNED_BIN_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen)
+{
+ if (*outlen < (unsigned long)mp_unsigned_bin_size(a)) {
+ return MP_VAL;
+ }
+ *outlen = mp_unsigned_bin_size(a);
+ return mp_to_unsigned_bin(a, b);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin_n.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_toom_mul.c b/crypto/userspace/libtommath/bn_mp_toom_mul.c
new file mode 100644
index 00000000000..ad5d9e9b649
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_toom_mul.c
@@ -0,0 +1,284 @@
+#include <tommath.h>
+#ifdef BN_MP_TOOM_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiplication using the Toom-Cook 3-way algorithm
+ *
+ * Much more complicated than Karatsuba but has a lower
+ * asymptotic running time of O(N**1.464). This algorithm is
+ * only particularly useful on VERY large inputs
+ * (we're talking 1000s of digits here...).
+*/
+int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2;
+ int res, B;
+
+ /* init temps */
+ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4,
+ &a0, &a1, &a2, &b0, &b1,
+ &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* B */
+ B = MIN(a->used, b->used) / 3;
+
+ /* a = a2 * B**2 + a1 * B + a0 */
+ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_copy(a, &a1)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a1, B);
+ mp_mod_2d(&a1, DIGIT_BIT * B, &a1);
+
+ if ((res = mp_copy(a, &a2)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a2, B*2);
+
+ /* b = b2 * B**2 + b1 * B + b0 */
+ if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_copy(b, &b1)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&b1, B);
+ mp_mod_2d(&b1, DIGIT_BIT * B, &b1);
+
+ if ((res = mp_copy(b, &b2)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&b2, B*2);
+
+ /* w0 = a0*b0 */
+ if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w4 = a2 * b2 */
+ if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */
+ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */
+ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+
+
+ /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */
+ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* now solve the matrix
+
+ 0 0 0 0 1
+ 1 2 4 8 16
+ 1 1 1 1 1
+ 16 8 4 2 1
+ 1 0 0 0 0
+
+ using 12 subtractions, 4 shifts,
+ 2 small divisions and 1 small multiplication
+ */
+
+ /* r1 - r4 */
+ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r0 */
+ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/2 */
+ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/2 */
+ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r2 - r0 - r4 */
+ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - 8r0 */
+ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - 8r4 */
+ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* 3r2 - r1 - r3 */
+ if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/3 */
+ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/3 */
+ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* at this point shift W[n] by B*n */
+ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear_multi(&w0, &w1, &w2, &w3, &w4,
+ &a0, &a1, &a2, &b0, &b1,
+ &b2, &tmp1, &tmp2, NULL);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_toom_mul.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_toom_sqr.c b/crypto/userspace/libtommath/bn_mp_toom_sqr.c
new file mode 100644
index 00000000000..48880d0350c
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_toom_sqr.c
@@ -0,0 +1,226 @@
+#include <tommath.h>
+#ifdef BN_MP_TOOM_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* squaring using Toom-Cook 3-way algorithm */
+int
+mp_toom_sqr(mp_int *a, mp_int *b)
+{
+ mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2;
+ int res, B;
+
+ /* init temps */
+ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* B */
+ B = a->used / 3;
+
+ /* a = a2 * B**2 + a1 * B + a0 */
+ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_copy(a, &a1)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a1, B);
+ mp_mod_2d(&a1, DIGIT_BIT * B, &a1);
+
+ if ((res = mp_copy(a, &a2)) != MP_OKAY) {
+ goto ERR;
+ }
+ mp_rshd(&a2, B*2);
+
+ /* w0 = a0*a0 */
+ if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w4 = a2 * a2 */
+ if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w1 = (a2 + 2(a1 + 2a0))**2 */
+ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* w3 = (a0 + 2(a1 + 2a2))**2 */
+ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+
+
+ /* w2 = (a2 + a1 + a0)**2 */
+ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* now solve the matrix
+
+ 0 0 0 0 1
+ 1 2 4 8 16
+ 1 1 1 1 1
+ 16 8 4 2 1
+ 1 0 0 0 0
+
+ using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication.
+ */
+
+ /* r1 - r4 */
+ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r0 */
+ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/2 */
+ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/2 */
+ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r2 - r0 - r4 */
+ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - 8r0 */
+ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - 8r4 */
+ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* 3r2 - r1 - r3 */
+ if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1 - r2 */
+ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3 - r2 */
+ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r1/3 */
+ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+ /* r3/3 */
+ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* at this point shift W[n] by B*n */
+ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) {
+ goto ERR;
+ }
+ if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL);
+ return res;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_toom_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_unsigned_bin_size.c b/crypto/userspace/libtommath/bn_mp_unsigned_bin_size.c
new file mode 100644
index 00000000000..6dc3bd5fc1b
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_unsigned_bin_size.c
@@ -0,0 +1,28 @@
+#include <tommath.h>
+#ifdef BN_MP_UNSIGNED_BIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* get the size for an unsigned equivalent */
+int mp_unsigned_bin_size (mp_int * a)
+{
+ int size = mp_count_bits (a);
+ return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_unsigned_bin_size.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_mp_zero.c b/crypto/userspace/libtommath/bn_mp_zero.c
new file mode 100644
index 00000000000..b0977d44316
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_mp_zero.c
@@ -0,0 +1,36 @@
+#include <tommath.h>
+#ifdef BN_MP_ZERO_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* set to zero */
+void mp_zero (mp_int * a)
+{
+ int n;
+ mp_digit *tmp;
+
+ a->sign = MP_ZPOS;
+ a->used = 0;
+
+ tmp = a->dp;
+ for (n = 0; n < a->alloc; n++) {
+ *tmp++ = 0;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_mp_zero.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_prime_tab.c b/crypto/userspace/libtommath/bn_prime_tab.c
new file mode 100644
index 00000000000..bd252477ec6
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_prime_tab.c
@@ -0,0 +1,61 @@
+#include <tommath.h>
+#ifdef BN_PRIME_TAB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+const mp_digit ltm_prime_tab[] = {
+ 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+ 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+ 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+ 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F,
+#ifndef MP_8BIT
+ 0x0083,
+ 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+ 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+ 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+ 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+ 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+ 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+ 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+ 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+ 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+ 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+ 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+ 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+ 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+ 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+ 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+ 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+ 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+ 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+ 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+ 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+ 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+ 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+ 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+ 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+ 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+ 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+ 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+ 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+#endif
+};
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_prime_tab.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_reverse.c b/crypto/userspace/libtommath/bn_reverse.c
new file mode 100644
index 00000000000..ddfa827a09f
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_reverse.c
@@ -0,0 +1,39 @@
+#include <tommath.h>
+#ifdef BN_REVERSE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* reverse an array, used for radix code */
+void
+bn_reverse (unsigned char *s, int len)
+{
+ int ix, iy;
+ unsigned char t;
+
+ ix = 0;
+ iy = len - 1;
+ while (ix < iy) {
+ t = s[ix];
+ s[ix] = s[iy];
+ s[iy] = t;
+ ++ix;
+ --iy;
+ }
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_reverse.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_s_mp_add.c b/crypto/userspace/libtommath/bn_s_mp_add.c
new file mode 100644
index 00000000000..f034ae62aad
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_s_mp_add.c
@@ -0,0 +1,109 @@
+#include <tommath.h>
+#ifdef BN_S_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+int
+s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int *x;
+ int olduse, res, min, max;
+
+ /* find sizes, we let |a| <= |b| which means we have to sort
+ * them. "x" will point to the input with the most digits
+ */
+ if (a->used > b->used) {
+ min = b->used;
+ max = a->used;
+ x = a;
+ } else {
+ min = a->used;
+ max = b->used;
+ x = b;
+ }
+
+ /* init result */
+ if (c->alloc < max + 1) {
+ if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* get old used digit count and set new one */
+ olduse = c->used;
+ c->used = max + 1;
+
+ {
+ register mp_digit u, *tmpa, *tmpb, *tmpc;
+ register int i;
+
+ /* alias for digit pointers */
+
+ /* first input */
+ tmpa = a->dp;
+
+ /* second input */
+ tmpb = b->dp;
+
+ /* destination */
+ tmpc = c->dp;
+
+ /* zero the carry */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+ *tmpc = *tmpa++ + *tmpb++ + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
+ */
+ if (min != max) {
+ for (; i < max; i++) {
+ /* T[i] = X[i] + U */
+ *tmpc = x->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* add carry */
+ *tmpc++ = u;
+
+ /* clear digits above oldused */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_add.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_s_mp_exptmod.c b/crypto/userspace/libtommath/bn_s_mp_exptmod.c
new file mode 100644
index 00000000000..097d894702b
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_s_mp_exptmod.c
@@ -0,0 +1,252 @@
+#include <tommath.h>
+#ifdef BN_S_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+#ifdef MP_LOW_MEM
+ #define TAB_SIZE 32
+#else
+ #define TAB_SIZE 256
+#endif
+
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res, mu;
+ mp_digit buf;
+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ int (*redux)(mp_int*,mp_int*,mp_int*);
+
+ /* find window size */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear (&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* create mu, used for Barrett reduction */
+ if ((err = mp_init (&mu)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+ if (redmode == 0) {
+ if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ redux = mp_reduce;
+ } else {
+ if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ redux = mp_reduce_2k_l;
+ }
+
+ /* create M table
+ *
+ * The M table contains powers of the base,
+ * e.g. M[x] = G**x mod P
+ *
+ * The first half of the table is not
+ * computed though accept for M[0] and M[1]
+ */
+ if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
+ */
+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ /* square it */
+ if ((err = mp_sqr (&M[1 << (winsize - 1)],
+ &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ /* reduce modulo P */
+ if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ }
+
+ /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+ * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+ */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ }
+
+ /* setup result */
+ if ((err = mp_init (&res)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ mp_set (&res, 1);
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset the bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int) DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+ mp_exch (&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_MU:mp_clear (&mu);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear (&M[x]);
+ }
+ return err;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_exptmod.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_s_mp_mul_digs.c b/crypto/userspace/libtommath/bn_s_mp_mul_digs.c
new file mode 100644
index 00000000000..f5bbf39ce24
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_s_mp_mul_digs.c
@@ -0,0 +1,90 @@
+#include <tommath.h>
+#ifdef BN_S_MP_MUL_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * many digits of output are created.
+ */
+int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ mp_int t;
+ int res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ /* can we use the fast multiplier? */
+ if (((digs) < MP_WARRAY) &&
+ MIN (a->used, b->used) <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_digs (a, b, c, digs);
+ }
+
+ if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
+ return res;
+ }
+ t.used = digs;
+
+ /* compute the digits of the product directly */
+ pa = a->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* set the carry to zero */
+ u = 0;
+
+ /* limit ourselves to making digs digits of output */
+ pb = MIN (b->used, digs - ix);
+
+ /* setup some aliases */
+ /* copy of the digit from a used within the nested loop */
+ tmpx = a->dp[ix];
+
+ /* an alias for the destination shifted ix places */
+ tmpt = t.dp + ix;
+
+ /* an alias for the digits of b */
+ tmpy = b->dp;
+
+ /* compute the columns of the output and propagate the carry */
+ for (iy = 0; iy < pb; iy++) {
+ /* compute the column as a mp_word */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* the new column is the lower part of the result */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry word from the result */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+ /* set carry if it is placed below digs */
+ if (ix + iy < digs) {
+ *tmpt = u;
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, c);
+
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_digs.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_s_mp_mul_high_digs.c b/crypto/userspace/libtommath/bn_s_mp_mul_high_digs.c
new file mode 100644
index 00000000000..2b718f23ccf
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_s_mp_mul_high_digs.c
@@ -0,0 +1,81 @@
+#include <tommath.h>
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+int
+s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ mp_int t;
+ int res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ /* can we use the fast multiplier? */
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ if (((a->used + b->used + 1) < MP_WARRAY)
+ && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_high_digs (a, b, c, digs);
+ }
+#endif
+
+ if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ t.used = a->used + b->used + 1;
+
+ pa = a->used;
+ pb = b->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* clear the carry */
+ u = 0;
+
+ /* left hand side of A[ix] * B[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias to the address of where the digits will be stored */
+ tmpt = &(t.dp[digs]);
+
+ /* alias for where to read the right hand side from */
+ tmpy = b->dp + (digs - ix);
+
+ for (iy = digs - ix; iy < pb; iy++) {
+ /* calculate the double precision result */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* get the lower part */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* carry the carry */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+ *tmpt = u;
+ }
+ mp_clamp (&t);
+ mp_exch (&t, c);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_high_digs.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_s_mp_sqr.c b/crypto/userspace/libtommath/bn_s_mp_sqr.c
new file mode 100644
index 00000000000..d2531c29255
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_s_mp_sqr.c
@@ -0,0 +1,84 @@
+#include <tommath.h>
+#ifdef BN_S_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+int s_mp_sqr (mp_int * a, mp_int * b)
+{
+ mp_int t;
+ int res, ix, iy, pa;
+ mp_word r;
+ mp_digit u, tmpx, *tmpt;
+
+ pa = a->used;
+ if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* default used is maximum possible size */
+ t.used = 2*pa + 1;
+
+ for (ix = 0; ix < pa; ix++) {
+ /* first calculate the digit at 2*ix */
+ /* calculate double precision result */
+ r = ((mp_word) t.dp[2*ix]) +
+ ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+ /* store lower part in result */
+ t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+ /* left hand side of A[ix] * A[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias for where to store the results */
+ tmpt = t.dp + (2*ix + 1);
+
+ for (iy = ix + 1; iy < pa; iy++) {
+ /* first calculate the product */
+ r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+ /* now calculate the double precision result, note we use
+ * addition instead of *2 since it's easier to optimize
+ */
+ r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+ /* store lower part */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ /* propagate upwards */
+ while (u != ((mp_digit) 0)) {
+ r = ((mp_word) *tmpt) + ((mp_word) u);
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, b);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_sqr.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bn_s_mp_sub.c b/crypto/userspace/libtommath/bn_s_mp_sub.c
new file mode 100644
index 00000000000..6a60c3932c4
--- /dev/null
+++ b/crypto/userspace/libtommath/bn_s_mp_sub.c
@@ -0,0 +1,89 @@
+#include <tommath.h>
+#ifdef BN_S_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+int
+s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int olduse, res, min, max;
+
+ /* find sizes */
+ min = b->used;
+ max = a->used;
+
+ /* init result */
+ if (c->alloc < max) {
+ if ((res = mp_grow (c, max)) != MP_OKAY) {
+ return res;
+ }
+ }
+ olduse = c->used;
+ c->used = max;
+
+ {
+ register mp_digit u, *tmpa, *tmpb, *tmpc;
+ register int i;
+
+ /* alias for digit pointers */
+ tmpa = a->dp;
+ tmpb = b->dp;
+ tmpc = c->dp;
+
+ /* set carry to zero */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* T[i] = A[i] - B[i] - U */
+ *tmpc = *tmpa++ - *tmpb++ - u;
+
+ /* U = carry bit of T[i]
+ * Note this saves performing an AND operation since
+ * if a carry does occur it will propagate all the way to the
+ * MSB. As a result a single shift is enough to get the carry
+ */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, e.g. if A has more digits than B */
+ for (; i < max; i++) {
+ /* T[i] = A[i] - U */
+ *tmpc = *tmpa++ - u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* clear digits above used (since we may not have grown result above) */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bn_s_mp_sub.c,v $ */
+/* $Revision: 1.4 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/bncore.c b/crypto/userspace/libtommath/bncore.c
new file mode 100644
index 00000000000..8fb1824c6f5
--- /dev/null
+++ b/crypto/userspace/libtommath/bncore.c
@@ -0,0 +1,36 @@
+#include <tommath.h>
+#ifdef BNCORE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* Known optimal configurations
+
+ CPU /Compiler /MUL CUTOFF/SQR CUTOFF
+-------------------------------------------------------------
+ Intel P4 Northwood /GCC v3.4.1 / 88/ 128/LTM 0.32 ;-)
+ AMD Athlon64 /GCC v3.4.4 / 80/ 120/LTM 0.35
+
+*/
+
+int KARATSUBA_MUL_CUTOFF = 80, /* Min. number of digits before Karatsuba multiplication is used. */
+ KARATSUBA_SQR_CUTOFF = 120, /* Min. number of digits before Karatsuba squaring is used. */
+
+ TOOM_MUL_CUTOFF = 350, /* no optimal values of these are known yet so set em high */
+ TOOM_SQR_CUTOFF = 400;
+#endif
+
+/* $Source: /cvs/libtom/libtommath/bncore.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:25:13 $ */
diff --git a/crypto/userspace/libtommath/changes.txt b/crypto/userspace/libtommath/changes.txt
new file mode 100644
index 00000000000..b0da4da4f91
--- /dev/null
+++ b/crypto/userspace/libtommath/changes.txt
@@ -0,0 +1,397 @@
+March 10th, 2007
+v0.41 -- Wolfgang Ehrhardt suggested a quick fix to mp_div_d() which makes the detection of powers of two quicker.
+ -- [CRI] Added libtommath.dsp for Visual C++ users.
+
+December 24th, 2006
+v0.40 -- Updated makefile to properly support LIBNAME
+ -- Fixed bug in fast_s_mp_mul_high_digs() which overflowed (line 83), thanks Valgrind!
+
+April 4th, 2006
+v0.39 -- Jim Wigginton pointed out my Montgomery examples in figures 6.4 and 6.6 were off by one, k should be 9 not 8
+ -- Bruce Guenter suggested I use --tag=CC for libtool builds where the compiler may think it's C++.
+ -- "mm" from sci.crypt pointed out that my mp_gcd was sub-optimal (I also updated and corrected the book)
+ -- updated some of the @@ tags in tommath.src to reflect source changes.
+ -- updated email and url info in all source files
+
+Jan 26th, 2006
+v0.38 -- broken makefile.shared fixed
+ -- removed some carry stores that were not required [updated text]
+
+November 18th, 2005
+v0.37 -- [Don Porter] reported on a TCL list [HEY SEND ME BUGREPORTS ALREADY!!!] that mp_add_d() would compute -0 with some inputs. Fixed.
+ -- [rinick@gmail.com] reported the makefile.bcc was messed up. Fixed.
+ -- [Kevin Kenny] reported some issues with mp_toradix_n(). Now it doesn't require a min of 3 chars of output.
+ -- Made the make command renamable. Wee
+
+August 1st, 2005
+v0.36 -- LTM_PRIME_2MSB_ON was fixed and the "OFF" flag was removed.
+ -- [Peter LaDow] found a typo in the XREALLOC macro
+ -- [Peter LaDow] pointed out that mp_read_(un)signed_bin should have "const" on the input
+ -- Ported LTC patch to fix the prime_random_ex() function to get the bitsize correct [and the maskOR flags]
+ -- Kevin Kenny pointed out a stray //
+ -- David Hulton pointed out a typo in the textbook [mp_montgomery_setup() pseudo-code]
+ -- Neal Hamilton (Elliptic Semiconductor) pointed out that my Karatsuba notation was backwards and that I could use
+ unsigned operations in the routine.
+ -- Paul Schmidt pointed out a linking error in mp_exptmod() when BN_S_MP_EXPTMOD_C is undefined (and another for read_radix)
+ -- Updated makefiles to be way more flexible
+
+March 12th, 2005
+v0.35 -- Stupid XOR function missing line again... oops.
+ -- Fixed bug in invmod not handling negative inputs correctly [Wolfgang Ehrhardt]
+ -- Made exteuclid always give positive u3 output...[ Wolfgang Ehrhardt ]
+ -- [Wolfgang Ehrhardt] Suggested a fix for mp_reduce() which avoided underruns. ;-)
+ -- mp_rand() would emit one too many digits and it was possible to get a 0 out of it ... oops
+ -- Added montgomery to the testing to make sure it handles 1..10 digit moduli correctly
+ -- Fixed bug in comba that would lead to possible erroneous outputs when "pa < digs"
+ -- Fixed bug in mp_toradix_size for "0" [Kevin Kenny]
+ -- Updated chapters 1-5 of the textbook ;-) It now talks about the new comba code!
+
+February 12th, 2005
+v0.34 -- Fixed two more small errors in mp_prime_random_ex()
+ -- Fixed overflow in mp_mul_d() [Kevin Kenny]
+ -- Added mp_to_(un)signed_bin_n() functions which do bounds checking for ya [and report the size]
+ -- Added "large" diminished radix support. Speeds up things like DSA where the moduli is of the form 2^k - P for some P < 2^(k/2) or so
+ Actually is faster than Montgomery on my AMD64 (and probably much faster on a P4)
+ -- Updated the manual a bit
+ -- Ok so I haven't done the textbook work yet... My current freelance gig has landed me in France till the
+ end of Feb/05. Once I get back I'll have tons of free time and I plan to go to town on the book.
+ As of this release the API will freeze. At least until the book catches up with all the changes. I welcome
+ bug reports but new algorithms will have to wait.
+
+December 23rd, 2004
+v0.33 -- Fixed "small" variant for mp_div() which would munge with negative dividends...
+ -- Fixed bug in mp_prime_random_ex() which would set the most significant byte to zero when
+ no special flags were set
+ -- Fixed overflow [minor] bug in fast_s_mp_sqr()
+ -- Made the makefiles easier to configure the group/user that ltm will install as
+ -- Fixed "final carry" bug in comba multipliers. (Volkan Ceylan)
+ -- Matt Johnston pointed out a missing semi-colon in mp_exptmod
+
+October 29th, 2004
+v0.32 -- Added "makefile.shared" for shared object support
+ -- Added more to the build options/configs in the manual
+ -- Started the Depends framework, wrote dep.pl to scan deps and
+ produce "callgraph.txt" ;-)
+ -- Wrote SC_RSA_1 which will enable close to the minimum required to perform
+ RSA on 32-bit [or 64-bit] platforms with LibTomCrypt
+ -- Merged in the small/slower mp_div replacement. You can now toggle which
+ you want to use as your mp_div() at build time. Saves roughly 8KB or so.
+ -- Renamed a few files and changed some comments to make depends system work better.
+ (No changes to function names)
+ -- Merged in new Combas that perform 2 reads per inner loop instead of the older
+ 3reads/2writes per inner loop of the old code. Really though if you want speed
+ learn to use TomsFastMath ;-)
+
+August 9th, 2004
+v0.31 -- "profiled" builds now :-) new timings for Intel Northwoods
+ -- Added "pretty" build target
+ -- Update mp_init() to actually assign 0's instead of relying on calloc()
+ -- "Wolfgang Ehrhardt" <Wolfgang.Ehrhardt@munich.netsurf.de> found a bug in mp_mul() where if
+ you multiply a negative by zero you get negative zero as the result. Oops.
+ -- J Harper from PeerSec let me toy with his AMD64 and I got 60-bit digits working properly
+ [this also means that I fixed a bug where if sizeof(int) < sizeof(mp_digit) it would bug]
+
+April 11th, 2004
+v0.30 -- Added "mp_toradix_n" which stores upto "n-1" least significant digits of an mp_int
+ -- Johan Lindh sent a patch so MSVC wouldn't whine about redefining malloc [in weird dll modes]
+ -- Henrik Goldman spotted a missing OPT_CAST in mp_fwrite()
+ -- Tuned tommath.h so that when MP_LOW_MEM is defined MP_PREC shall be reduced.
+ [I also allow MP_PREC to be externally defined now]
+ -- Sped up mp_cnt_lsb() by using a 4x4 table [e.g. 4x speedup]
+ -- Added mp_prime_random_ex() which is a more versatile prime generator accurate to
+ exact bit lengths (unlike the deprecated but still available mp_prime_random() which
+ is only accurate to byte lengths). See the new LTM_PRIME_* flags ;-)
+ -- Alex Polushin contributed an optimized mp_sqrt() as well as mp_get_int() and mp_is_square().
+ I've cleaned them all up to be a little more consistent [along with one bug fix] for this release.
+ -- Added mp_init_set and mp_init_set_int to initialize and set small constants with one function
+ call.
+ -- Removed /etclib directory [um LibTomPoly deprecates this].
+ -- Fixed mp_mod() so the sign of the result agrees with the sign of the modulus.
+ ++ N.B. My semester is almost up so expect updates to the textbook to be posted to the libtomcrypt.org
+ website.
+
+Jan 25th, 2004
+v0.29 ++ Note: "Henrik" from the v0.28 changelog refers to Henrik Goldman ;-)
+ -- Added fix to mp_shrink to prevent a realloc when used == 0 [e.g. realloc zero bytes???]
+ -- Made the mp_prime_rabin_miller_trials() function internal table smaller and also
+ set the minimum number of tests to two (sounds a bit safer).
+ -- Added a mp_exteuclid() which computes the extended euclidean algorithm.
+ -- Fixed a memory leak in s_mp_exptmod() [called when Barrett reduction is to be used] which would arise
+ if a multiplication or subsequent reduction failed [would not free the temp result].
+ -- Made an API change to mp_radix_size(). It now returns an error code and stores the required size
+ through an "int star" passed to it.
+
+Dec 24th, 2003
+v0.28 -- Henrik Goldman suggested I add casts to the montomgery code [stores into mu...] so compilers wouldn't
+ spew [erroneous] diagnostics... fixed.
+ -- Henrik Goldman also spotted two typos. One in mp_radix_size() and another in mp_toradix().
+ -- Added fix to mp_shrink() to avoid a memory leak.
+ -- Added mp_prime_random() which requires a callback to make truly random primes of a given nature
+ (idea from chat with Niels Ferguson at Crypto'03)
+ -- Picked up a second wind. I'm filled with Gooo. Mission Gooo!
+ -- Removed divisions from mp_reduce_is_2k()
+ -- Sped up mp_div_d() [general case] to use only one division per digit instead of two.
+ -- Added the heap macros from LTC to LTM. Now you can easily [by editing four lines of tommath.h]
+ change the name of the heap functions used in LTM [also compatible with LTC via MPI mode]
+ -- Added bn_prime_rabin_miller_trials() which gives the number of Rabin-Miller trials to achieve
+ a failure rate of less than 2^-96
+ -- fixed bug in fast_mp_invmod(). The initial testing logic was wrong. An invalid input is not when
+ "a" and "b" are even it's when "b" is even [the algo is for odd moduli only].
+ -- Started a new manual [finally]. It is incomplete and will be finished as time goes on. I had to stop
+ adding full demos around half way in chapter three so I could at least get a good portion of the
+ manual done. If you really need help using the library you can always email me!
+ -- My Textbook is now included as part of the package [all Public Domain]
+
+Sept 19th, 2003
+v0.27 -- Removed changes.txt~ which was made by accident since "kate" decided it was
+ a good time to re-enable backups... [kde is fun!]
+ -- In mp_grow() "a->dp" is not overwritten by realloc call [re: memory leak]
+ Now if mp_grow() fails the mp_int is still valid and can be cleared via
+ mp_clear() to reclaim the memory.
+ -- Henrik Goldman found a buffer overflow bug in mp_add_d(). Fixed.
+ -- Cleaned up mp_mul_d() to be much easier to read and follow.
+
+Aug 29th, 2003
+v0.26 -- Fixed typo that caused warning with GCC 3.2
+ -- Martin Marcel noticed a bug in mp_neg() that allowed negative zeroes.
+ Also, Martin is the fellow who noted the bugs in mp_gcd() of 0.24/0.25.
+ -- Martin Marcel noticed an optimization [and slight bug] in mp_lcm().
+ -- Added fix to mp_read_unsigned_bin to prevent a buffer overflow.
+ -- Beefed up the comments in the baseline multipliers [and montgomery]
+ -- Added "mont" demo to the makefile.msvc in etc/
+ -- Optimized sign compares in mp_cmp from 4 to 2 cases.
+
+Aug 4th, 2003
+v0.25 -- Fix to mp_gcd again... oops (0,-a) == (-a, 0) == a
+ -- Fix to mp_clear which didn't reset the sign [Greg Rose]
+ -- Added mp_error_to_string() to convert return codes to strings. [Greg Rose]
+ -- Optimized fast_mp_invmod() to do the test for invalid inputs [both even]
+ first so temps don't have to be initialized if it's going to fail.
+ -- Optimized mp_gcd() by removing mp_div_2d calls for when one of the inputs
+ is odd.
+ -- Tons of new comments, some indentation fixups, etc.
+ -- mp_jacobi() returns MP_VAL if the modulus is less than or equal to zero.
+ -- fixed two typos in the header of each file :-)
+ -- LibTomMath is officially Public Domain [see LICENSE]
+
+July 15th, 2003
+v0.24 -- Optimized mp_add_d and mp_sub_d to not allocate temporary variables
+ -- Fixed mp_gcd() so the gcd of 0,0 is 0. Allows the gcd operation to be chained
+ e.g. (0,0,a) == a [instead of 1]
+ -- Should be one of the last release for a while. Working on LibTomMath book now.
+ -- optimized the pprime demo [/etc/pprime.c] to first make a huge table of single
+ digit primes then it reads them randomly instead of randomly choosing/testing single
+ digit primes.
+
+July 12th, 2003
+v0.23 -- Optimized mp_prime_next_prime() to not use mp_mod [via is_divisible()] in each
+ iteration. Instead now a smaller table is kept of the residues which can be updated
+ without division.
+ -- Fixed a bug in next_prime() where an input of zero would be treated as odd and
+ have two added to it [to move to the next odd].
+ -- fixed a bug in prime_fermat() and prime_miller_rabin() which allowed the base
+ to be negative, zero or one. Normally the test is only valid if the base is
+ greater than one.
+ -- changed the next_prime() prototype to accept a new parameter "bbs_style" which
+ will find the next prime congruent to 3 mod 4. The default [bbs_style==0] will
+ make primes which are either congruent to 1 or 3 mod 4.
+ -- fixed mp_read_unsigned_bin() so that it doesn't include both code for
+ the case DIGIT_BIT < 8 and >= 8
+ -- optimized div_d() to easy out on division by 1 [or if a == 0] and use
+ logical shifts if the divisor is a power of two.
+ -- the default DIGIT_BIT type was not int for non-default builds. Fixed.
+
+July 2nd, 2003
+v0.22 -- Fixed up mp_invmod so the result is properly in range now [was always congruent to the inverse...]
+ -- Fixed up s_mp_exptmod and mp_exptmod_fast so the lower half of the pre-computed table isn't allocated
+ which makes the algorithm use half as much ram.
+ -- Fixed the install script not to make the book :-) [which isn't included anyways]
+ -- added mp_cnt_lsb() which counts how many of the lsbs are zero
+ -- optimized mp_gcd() to use the new mp_cnt_lsb() to replace multiple divisions by two by a single division.
+ -- applied similar optimization to mp_prime_miller_rabin().
+ -- Fixed a bug in both mp_invmod() and fast_mp_invmod() which tested for odd
+ via "mp_iseven() == 0" which is not valid [since zero is not even either].
+
+June 19th, 2003
+v0.21 -- Fixed bug in mp_mul_d which would not handle sign correctly [would not always forward it]
+ -- Removed the #line lines from gen.pl [was in violation of ISO C]
+
+June 8th, 2003
+v0.20 -- Removed the book from the package. Added the TDCAL license document.
+ -- This release is officially pure-bred TDCAL again [last officially TDCAL based release was v0.16]
+
+June 6th, 2003
+v0.19 -- Fixed a bug in mp_montgomery_reduce() which was introduced when I tweaked mp_rshd() in the previous release.
+ Essentially the digits were not trimmed before the compare which cause a subtraction to occur all the time.
+ -- Fixed up etc/tune.c a bit to stop testing new cutoffs after 16 failures [to find more optimal points].
+ Brute force ho!
+
+
+May 29th, 2003
+v0.18 -- Fixed a bug in s_mp_sqr which would handle carries properly just not very elegantly.
+ (e.g. correct result, just bad looking code)
+ -- Fixed bug in mp_sqr which still had a 512 constant instead of MP_WARRAY
+ -- Added Toom-Cook multipliers [needs tuning!]
+ -- Added efficient divide by 3 algorithm mp_div_3
+ -- Re-wrote mp_div_d to be faster than calling mp_div
+ -- Added in a donated BCC makefile and a single page LTM poster (ahalhabsi@sbcglobal.net)
+ -- Added mp_reduce_2k which reduces an input modulo n = 2**p - k for any single digit k
+ -- Made the exptmod system be aware of the 2k reduction algorithms.
+ -- Rewrote mp_dr_reduce to be smaller, simpler and easier to understand.
+
+May 17th, 2003
+v0.17 -- Benjamin Goldberg submitted optimized mp_add and mp_sub routines. A new gen.pl as well
+ as several smaller suggestions. Thanks!
+ -- removed call to mp_cmp in inner loop of mp_div and put mp_cmp_mag in its place :-)
+ -- Fixed bug in mp_exptmod that would cause it to fail for odd moduli when DIGIT_BIT != 28
+ -- mp_exptmod now also returns errors if the modulus is negative and will handle negative exponents
+ -- mp_prime_is_prime will now return true if the input is one of the primes in the prime table
+ -- Damian M Gryski (dgryski@uwaterloo.ca) found a index out of bounds error in the
+ mp_fast_s_mp_mul_high_digs function which didn't come up before. (fixed)
+ -- Refactored the DR reduction code so there is only one function per file.
+ -- Fixed bug in the mp_mul() which would erroneously avoid the faster multiplier [comba] when it was
+ allowed. The bug would not cause the incorrect value to be produced just less efficient (fixed)
+ -- Fixed similar bug in the Montgomery reduction code.
+ -- Added tons of (mp_digit) casts so the 7/15/28/31 bit digit code will work flawlessly out of the box.
+ Also added limited support for 64-bit machines with a 60-bit digit. Both thanks to Tom Wu (tom@arcot.com)
+ -- Added new comments here and there, cleaned up some code [style stuff]
+ -- Fixed a lingering typo in mp_exptmod* that would set bitcnt to zero then one. Very silly stuff :-)
+ -- Fixed up mp_exptmod_fast so it would set "redux" to the comba Montgomery reduction if allowed. This
+ saves quite a few calls and if statements.
+ -- Added etc/mont.c a test of the Montgomery reduction [assuming all else works :-| ]
+ -- Fixed up etc/tune.c to use a wider test range [more appropriate] also added a x86 based addition which
+ uses RDTSC for high precision timing.
+ -- Updated demo/demo.c to remove MPI stuff [won't work anyways], made the tests run for 2 seconds each so its
+ not so insanely slow. Also made the output space delimited [and fixed up various errors]
+ -- Added logs directory, logs/graph.dem which will use gnuplot to make a series of PNG files
+ that go with the pre-made index.html. You have to build [via make timing] and run ltmtest first in the
+ root of the package.
+ -- Fixed a bug in mp_sub and mp_add where "-a - -a" or "-a + a" would produce -0 as the result [obviously invalid].
+ -- Fixed a bug in mp_rshd. If the count == a.used it should zero/return [instead of shifting]
+ -- Fixed a "off-by-one" bug in mp_mul2d. The initial size check on alloc would be off by one if the residue
+ shifting caused a carry.
+ -- Fixed a bug where s_mp_mul_digs() would not call the Comba based routine if allowed. This made Barrett reduction
+ slower than it had to be.
+
+Mar 29th, 2003
+v0.16 -- Sped up mp_div by making normalization one shift call
+ -- Sped up mp_mul_2d/mp_div_2d by aliasing pointers :-)
+ -- Cleaned up mp_gcd to use the macros for odd/even detection
+ -- Added comments here and there, mostly there but occasionally here too.
+
+Mar 22nd, 2003
+v0.15 -- Added series of prime testing routines to lib
+ -- Fixed up etc/tune.c
+ -- Added DR reduction algorithm
+ -- Beefed up the manual more.
+ -- Fixed up demo/demo.c so it doesn't have so many warnings and it does the full series of
+ tests
+ -- Added "pre-gen" directory which will hold a "gen.pl"'ed copy of the entire lib [done at
+ zipup time so its always the latest]
+ -- Added conditional casts for C++ users [boo!]
+
+Mar 15th, 2003
+v0.14 -- Tons of manual updates
+ -- cleaned up the directory
+ -- added MSVC makefiles
+ -- source changes [that I don't recall]
+ -- Fixed up the lshd/rshd code to use pointer aliasing
+ -- Fixed up the mul_2d and div_2d to not call rshd/lshd unless needed
+ -- Fixed up etc/tune.c a tad
+ -- fixed up demo/demo.c to output comma-delimited results of timing
+ also fixed up timing demo to use a finer granularity for various functions
+ -- fixed up demo/demo.c testing to pause during testing so my Duron won't catch on fire
+ [stays around 31-35C during testing :-)]
+
+Feb 13th, 2003
+v0.13 -- tons of minor speed-ups in low level add, sub, mul_2 and div_2 which propagate
+ to other functions like mp_invmod, mp_div, etc...
+ -- Sped up mp_exptmod_fast by using new code to find R mod m [e.g. B^n mod m]
+ -- minor fixes
+
+Jan 17th, 2003
+v0.12 -- re-wrote the majority of the makefile so its more portable and will
+ install via "make install" on most *nix platforms
+ -- Re-packaged all the source as seperate files. Means the library a single
+ file packagage any more. Instead of just adding "bn.c" you have to add
+ libtommath.a
+ -- Renamed "bn.h" to "tommath.h"
+ -- Changes to the manual to reflect all of this
+ -- Used GNU Indent to clean up the source
+
+Jan 15th, 2003
+v0.11 -- More subtle fixes
+ -- Moved to gentoo linux [hurrah!] so made *nix specific fixes to the make process
+ -- Sped up the montgomery reduction code quite a bit
+ -- fixed up demo so when building timing for the x86 it assumes ELF format now
+
+Jan 9th, 2003
+v0.10 -- Pekka Riikonen suggested fixes to the radix conversion code.
+ -- Added baseline montgomery and comba montgomery reductions, sped up exptmods
+ [to a point, see bn.h for MONTGOMERY_EXPT_CUTOFF]
+
+Jan 6th, 2003
+v0.09 -- Updated the manual to reflect recent changes. :-)
+ -- Added Jacobi function (mp_jacobi) to supplement the number theory side of the lib
+ -- Added a Mersenne prime finder demo in ./etc/mersenne.c
+
+Jan 2nd, 2003
+v0.08 -- Sped up the multipliers by moving the inner loop variables into a smaller scope
+ -- Corrected a bunch of small "warnings"
+ -- Added more comments
+ -- Made "mtest" be able to use /dev/random, /dev/urandom or stdin for RNG data
+ -- Corrected some bugs where error messages were potentially ignored
+ -- add etc/pprime.c program which makes numbers which are provably prime.
+
+Jan 1st, 2003
+v0.07 -- Removed alot of heap operations from core functions to speed them up
+ -- Added a root finding function [and mp_sqrt macro like from MPI]
+ -- Added more to manual
+
+Dec 31st, 2002
+v0.06 -- Sped up the s_mp_add, s_mp_sub which inturn sped up mp_invmod, mp_exptmod, etc...
+ -- Cleaned up the header a bit more
+
+Dec 30th, 2002
+v0.05 -- Builds with MSVC out of the box
+ -- Fixed a bug in mp_invmod w.r.t. even moduli
+ -- Made mp_toradix and mp_read_radix use char instead of unsigned char arrays
+ -- Fixed up exptmod to use fewer multiplications
+ -- Fixed up mp_init_size to use only one heap operation
+ -- Note there is a slight "off-by-one" bug in the library somewhere
+ without the padding (see the source for comment) the library
+ crashes in libtomcrypt. Anyways a reasonable workaround is to pad the
+ numbers which will always correct it since as the numbers grow the padding
+ will still be beyond the end of the number
+ -- Added more to the manual
+
+Dec 29th, 2002
+v0.04 -- Fixed a memory leak in mp_to_unsigned_bin
+ -- optimized invmod code
+ -- Fixed bug in mp_div
+ -- use exchange instead of copy for results
+ -- added a bit more to the manual
+
+Dec 27th, 2002
+v0.03 -- Sped up s_mp_mul_high_digs by not computing the carries of the lower digits
+ -- Fixed a bug where mp_set_int wouldn't zero the value first and set the used member.
+ -- fixed a bug in s_mp_mul_high_digs where the limit placed on the result digits was not calculated properly
+ -- fixed bugs in add/sub/mul/sqr_mod functions where if the modulus and dest were the same it wouldn't work
+ -- fixed a bug in mp_mod and mp_mod_d concerning negative inputs
+ -- mp_mul_d didn't preserve sign
+ -- Many many many many fixes
+ -- Works in LibTomCrypt now :-)
+ -- Added iterations to the timing demos... more accurate.
+ -- Tom needs a job.
+
+Dec 26th, 2002
+v0.02 -- Fixed a few "slips" in the manual. This is "LibTomMath" afterall :-)
+ -- Added mp_cmp_mag, mp_neg, mp_abs and mp_radix_size that were missing.
+ -- Sped up the fast [comba] multipliers more [yahoo!]
+
+Dec 25th,2002
+v0.01 -- Initial release. Gimme a break.
+ -- Todo list,
+ add details to manual [e.g. algorithms]
+ more comments in code
+ example programs
diff --git a/crypto/userspace/libtommath/pretty.build b/crypto/userspace/libtommath/pretty.build
new file mode 100644
index 00000000000..a708b8af221
--- /dev/null
+++ b/crypto/userspace/libtommath/pretty.build
@@ -0,0 +1,66 @@
+#!/bin/perl -w
+#
+# Cute little builder for perl
+# Total waste of development time...
+#
+# This will build all the object files and then the archive .a file
+# requires GCC, GNU make and a sense of humour.
+#
+# Tom St Denis
+use strict;
+
+my $count = 0;
+my $starttime = time;
+my $rate = 0;
+print "Scanning for source files...\n";
+foreach my $filename (glob "*.c") {
+ ++$count;
+}
+print "Source files to build: $count\nBuilding...\n";
+my $i = 0;
+my $lines = 0;
+my $filesbuilt = 0;
+foreach my $filename (glob "*.c") {
+ printf("Building %3.2f%%, ", (++$i/$count)*100.0);
+ if ($i % 4 == 0) { print "/, "; }
+ if ($i % 4 == 1) { print "-, "; }
+ if ($i % 4 == 2) { print "\\, "; }
+ if ($i % 4 == 3) { print "|, "; }
+ if ($rate > 0) {
+ my $tleft = ($count - $i) / $rate;
+ my $tsec = $tleft%60;
+ my $tmin = ($tleft/60)%60;
+ my $thour = ($tleft/3600)%60;
+ printf("%2d:%02d:%02d left, ", $thour, $tmin, $tsec);
+ }
+ my $cnt = ($i/$count)*30.0;
+ my $x = 0;
+ print "[";
+ for (; $x < $cnt; $x++) { print "#"; }
+ for (; $x < 30; $x++) { print " "; }
+ print "]\r";
+ my $tmp = $filename;
+ $tmp =~ s/\.c/".o"/ge;
+ if (open(SRC, "<$tmp")) {
+ close SRC;
+ } else {
+ !system("make $tmp > /dev/null 2>/dev/null") or die "\nERROR: Failed to make $tmp!!!\n";
+ open( SRC, "<$filename" ) or die "Couldn't open $filename for reading: $!";
+ ++$lines while (<SRC>);
+ close SRC or die "Error closing $filename after reading: $!";
+ ++$filesbuilt;
+ }
+
+ # update timer
+ if (time != $starttime) {
+ my $delay = time - $starttime;
+ $rate = $i/$delay;
+ }
+}
+
+# finish building the library
+printf("\nFinished building source (%d seconds, %3.2f files per second).\n", time - $starttime, $rate);
+print "Compiled approximately $filesbuilt files and $lines lines of code.\n";
+print "Doing final make (building archive...)\n";
+!system("make > /dev/null 2>/dev/null") or die "\nERROR: Failed to perform last make command!!!\n";
+print "done.\n"; \ No newline at end of file
diff --git a/crypto/userspace/libtommath/tommath.h b/crypto/userspace/libtommath/tommath.h
new file mode 100644
index 00000000000..3fa7ae89853
--- /dev/null
+++ b/crypto/userspace/libtommath/tommath.h
@@ -0,0 +1,569 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com
+ */
+#ifndef BN_H_
+#define BN_H_
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/math64.h>
+
+#define CHAR_BIT sizeof(uint8_t)*8
+
+inline static int rand(void)
+{
+ int res;
+
+ get_random_bytes(&res, sizeof(int));
+
+ return res;
+}
+
+#include <tommath_class.h>
+
+#ifndef MIN
+ #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+ #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+
+/* C++ compilers don't like assigning void * to mp_digit * */
+#define OPT_CAST(x) (x *)
+
+#else
+
+/* C on the other hand doesn't care */
+#define OPT_CAST(x)
+
+#endif
+
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+
+/* FIXME: This can be improved, but requires to use 128bit division
+ * on 64bit machines, which is not available in kernel now.
+ */
+#if BITS_PER_LONG < 32
+
+ typedef uint16_t mp_digit;
+ typedef uint32_t mp_word;
+# define DIGIT_BIT 15
+
+#elif BITS_PER_LONG <= 64
+
+ typedef uint32_t mp_digit;
+ typedef uint64_t mp_word;
+
+# define word_div_int(x,y) div_u64((x),(y))
+
+# define DIGIT_BIT 31
+
+#endif
+
+#if 0
+ /* if we could get a way to use an 128 bit integer
+ * in kernel, use this.
+ */
+ typedef uint64_t mp_digit;
+ typedef __uint128_t mp_word;
+# define DIGIT_BIT 60
+
+#endif
+
+#ifndef word_div_int
+# define word_div_int(x,y) ((x)/(y))
+#endif
+
+
+/* define heap macros */
+#ifndef XMALLOC
+# define XMALLOC(x) kmalloc(x, GFP_KERNEL)
+# define XFREE kfree
+# define XREALLOC(x,y) krealloc(x,y, GFP_KERNEL)
+# define XCALLOC(x,y) kzalloc(x*y, GPF_KERNEL)
+#endif
+
+/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */
+#ifndef DIGIT_BIT
+// #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
+#endif
+
+#define MP_DIGIT_BIT DIGIT_BIT
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/* equalities */
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+
+#define MP_OKAY 0 /* ok result */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+#define MP_RANGE MP_VAL
+
+#define MP_YES 1 /* yes response */
+#define MP_NO 0 /* no response */
+
+/* Primality generation flags */
+#define LTM_PRIME_BBS 0x0001 /* BBS style prime */
+#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
+#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
+
+typedef int mp_err;
+
+/* you'll have to tune these... */
+extern int KARATSUBA_MUL_CUTOFF,
+ KARATSUBA_SQR_CUTOFF,
+ TOOM_MUL_CUTOFF,
+ TOOM_SQR_CUTOFF;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+/* We use this to reduce stack usage --nmav */
+#define MP_LOW_MEM
+
+/* default precision */
+#ifndef MP_PREC
+ #ifndef MP_LOW_MEM
+ #define MP_PREC 32 /* default digits of precision */
+ #else
+ #define MP_PREC 8 /* default digits of precision */
+ #endif
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct {
+ int used, alloc, sign;
+ mp_digit *dp;
+} mp_int;
+
+/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
+
+
+#define USED(m) ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m) ((m)->sign)
+
+/* error code to char* string */
+char *mp_error_to_string(int code);
+
+/* ---> init and deinit bignum functions <--- */
+/* init a bignum */
+int mp_init(mp_int *a);
+
+/* free a bignum */
+void mp_clear(mp_int *a);
+
+/* init a null terminated series of arguments */
+int mp_init_multi(mp_int *mp, ...);
+
+/* clear a null terminated series of arguments */
+void mp_clear_multi(mp_int *mp, ...);
+
+/* exchange two ints */
+void mp_exch(mp_int *a, mp_int *b);
+
+/* shrink ram required for a bignum */
+int mp_shrink(mp_int *a);
+
+/* grow an int to a given size */
+int mp_grow(mp_int *a, int size);
+
+/* init to a given number of digits */
+int mp_init_size(mp_int *a, int size);
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+/* set to zero */
+void mp_zero(mp_int *a);
+
+/* set to a digit */
+void mp_set(mp_int *a, mp_digit b);
+
+/* set a 32-bit const */
+int mp_set_int(mp_int *a, unsigned long b);
+
+/* get a 32-bit value */
+unsigned long mp_get_int(mp_int * a);
+
+/* initialize and set a digit */
+int mp_init_set (mp_int * a, mp_digit b);
+
+/* initialize and set 32-bit value */
+int mp_init_set_int (mp_int * a, unsigned long b);
+
+/* copy, b = a */
+int mp_copy(mp_int *a, mp_int *b);
+
+/* inits and copies, a = b */
+int mp_init_copy(mp_int *a, mp_int *b);
+
+/* trim unused digits */
+void mp_clamp(mp_int *a);
+
+/* ---> digit manipulation <--- */
+
+/* right shift by "b" digits */
+void mp_rshd(mp_int *a, int b);
+
+/* left shift by "b" digits */
+int mp_lshd(mp_int *a, int b);
+
+/* c = a / 2**b */
+int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d);
+
+/* b = a/2 */
+int mp_div_2(mp_int *a, mp_int *b);
+
+/* c = a * 2**b */
+int mp_mul_2d(mp_int *a, int b, mp_int *c);
+
+/* b = a*2 */
+int mp_mul_2(mp_int *a, mp_int *b);
+
+/* c = a mod 2**d */
+int mp_mod_2d(mp_int *a, int b, mp_int *c);
+
+/* computes a = 2**b */
+int mp_2expt(mp_int *a, int b);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a);
+
+/* I Love Earth! */
+
+/* makes a pseudo-random int of a given size */
+int mp_rand(mp_int *a, int digits);
+
+/* ---> binary operations <--- */
+/* c = a XOR b */
+int mp_xor(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a OR b */
+int mp_or(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a AND b */
+int mp_and(mp_int *a, mp_int *b, mp_int *c);
+
+/* ---> Basic arithmetic <--- */
+
+/* b = -a */
+int mp_neg(mp_int *a, mp_int *b);
+
+/* b = |a| */
+int mp_abs(mp_int *a, mp_int *b);
+
+/* compare a to b */
+int mp_cmp(mp_int *a, mp_int *b);
+
+/* compare |a| to |b| */
+int mp_cmp_mag(mp_int *a, mp_int *b);
+
+/* c = a + b */
+int mp_add(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a - b */
+int mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a * b */
+int mp_mul(mp_int *a, mp_int *b, mp_int *c);
+
+/* b = a*a */
+int mp_sqr(mp_int *a, mp_int *b);
+
+/* a/b => cb + d == a */
+int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod(mp_int *a, mp_int *b, mp_int *c);
+
+/* ---> single digit functions <--- */
+
+/* compare against a single digit */
+int mp_cmp_d(mp_int *a, mp_digit b);
+
+/* c = a + b */
+int mp_add_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a - b */
+int mp_sub_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a * b */
+int mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* a/b => cb + d == a */
+int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d);
+
+/* a/3 => 3c + d == a */
+int mp_div_3(mp_int *a, mp_int *c, mp_digit *d);
+
+/* c = a**b */
+int mp_expt_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c);
+
+/* ---> number theory <--- */
+
+/* d = a + b (mod c) */
+int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* d = a - b (mod c) */
+int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* d = a * b (mod c) */
+int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* c = a * a (mod b) */
+int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = 1/a (mod b) */
+int mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = (a, b) */
+int mp_gcd(mp_int *a, mp_int *b, mp_int *c);
+
+/* produces value such that U1*a + U2*b = U3 */
+int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3);
+
+/* c = [a, b] or (a*b)/(a, b) */
+int mp_lcm(mp_int *a, mp_int *b, mp_int *c);
+
+/* finds one of the b'th root of a, such that |c|**b <= |a|
+ *
+ * returns error if a < 0 and b is even
+ */
+int mp_n_root(mp_int *a, mp_digit b, mp_int *c);
+
+/* special sqrt algo */
+int mp_sqrt(mp_int *arg, mp_int *ret);
+
+/* is number a square? */
+int mp_is_square(mp_int *arg, int *ret);
+
+/* computes the jacobi c = (a | n) (or Legendre if b is prime) */
+int mp_jacobi(mp_int *a, mp_int *n, int *c);
+
+/* used to setup the Barrett reduction for a given modulus b */
+int mp_reduce_setup(mp_int *a, mp_int *b);
+
+/* Barrett Reduction, computes a (mod b) with a precomputed value c
+ *
+ * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely
+ * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code].
+ */
+int mp_reduce(mp_int *a, mp_int *b, mp_int *c);
+
+/* setups the montgomery reduction */
+int mp_montgomery_setup(mp_int *a, mp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+int mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+
+/* returns 1 if a is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a);
+
+/* sets the value of "d" required for mp_dr_reduce */
+void mp_dr_setup(mp_int *a, mp_digit *d);
+
+/* reduces a modulo b using the Diminished Radix method */
+int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp);
+
+/* returns true if a can be reduced with mp_reduce_2k */
+int mp_reduce_is_2k(mp_int *a);
+
+/* determines k value for 2k reduction */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d);
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
+
+/* returns true if a can be reduced with mp_reduce_2k_l */
+int mp_reduce_is_2k_l(mp_int *a);
+
+/* determines k value for 2k reduction */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+
+/* d = a**b (mod c) */
+int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* ---> Primes <--- */
+
+/* number of primes */
+#ifdef MP_8BIT
+ #define PRIME_SIZE 31
+#else
+ #define PRIME_SIZE 256
+#endif
+
+/* table of first PRIME_SIZE primes */
+extern const mp_digit ltm_prime_tab[];
+
+/* result=1 if a is divisible by one of the first PRIME_SIZE primes */
+int mp_prime_is_divisible(mp_int *a, int *result);
+
+/* performs one Fermat test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+int mp_prime_fermat(mp_int *a, mp_int *b, int *result);
+
+/* performs one Miller-Rabin test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result);
+
+/* This gives [for a given bit size] the number of trials required
+ * such that Miller-Rabin gives a prob of failure lower than 2^-96
+ */
+int mp_prime_rabin_miller_trials(int size);
+
+/* performs t rounds of Miller-Rabin on "a" using the first
+ * t prime bases. Also performs an initial sieve of trial
+ * division. Determines if "a" is prime with probability
+ * of error no more than (1/4)**t.
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime(mp_int *a, int t, int *result);
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+int mp_prime_next_prime(mp_int *a, int t, int bbs_style);
+
+/* makes a truly random prime of a given size (bytes),
+ * call with bbs = 1 if you want it to be congruent to 3 mod 4
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ * The prime generated will be larger than 2^(8*size).
+ */
+#define mp_prime_random(a, t, size, bbs, cb, dat) mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat)
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * LTM_PRIME_BBS - make prime congruent to 3 mod 4
+ * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
+ * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero
+ * LTM_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat);
+
+/* ---> radix conversion <--- */
+int mp_count_bits(mp_int *a);
+
+int mp_unsigned_bin_size(mp_int *a);
+int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c);
+int mp_to_unsigned_bin(mp_int *a, unsigned char *b);
+int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen);
+
+int mp_signed_bin_size(mp_int *a);
+int mp_read_signed_bin(mp_int *a, const unsigned char *b, int c);
+int mp_to_signed_bin(mp_int *a, unsigned char *b);
+int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen);
+
+int mp_read_radix(mp_int *a, const char *str, int radix);
+int mp_toradix(mp_int *a, char *str, int radix);
+int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen);
+int mp_radix_size(mp_int *a, int radix, int *size);
+
+#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
+#define mp_raw_size(mp) mp_signed_bin_size(mp)
+#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str))
+#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp) mp_unsigned_bin_size(mp)
+#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str))
+
+#define mp_tobinary(M, S) mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S) mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S) mp_toradix((M), (S), 16)
+
+/* lowlevel functions, do not call! */
+int s_mp_add(mp_int *a, mp_int *b, mp_int *c);
+int s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int fast_s_mp_sqr(mp_int *a, mp_int *b);
+int s_mp_sqr(mp_int *a, mp_int *b);
+int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c);
+int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c);
+int mp_karatsuba_sqr(mp_int *a, mp_int *b);
+int mp_toom_sqr(mp_int *a, mp_int *b);
+int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
+int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode);
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int mode);
+void bn_reverse(unsigned char *s, int len);
+
+extern const char *mp_s_rmap;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtommath/tommath.h,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/03/31 14:18:44 $ */
diff --git a/crypto/userspace/libtommath/tommath_class.h b/crypto/userspace/libtommath/tommath_class.h
new file mode 100644
index 00000000000..166dd80e5ea
--- /dev/null
+++ b/crypto/userspace/libtommath/tommath_class.h
@@ -0,0 +1,999 @@
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#if defined(LTM2)
+#define LTM3
+#endif
+#if defined(LTM1)
+#define LTM2
+#endif
+#define LTM1
+
+#if defined(LTM_ALL)
+#define BN_ERROR_C
+#define BN_FAST_MP_INVMOD_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_FAST_S_MP_MUL_DIGS_C
+#define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+#define BN_FAST_S_MP_SQR_C
+#define BN_MP_2EXPT_C
+#define BN_MP_ABS_C
+#define BN_MP_ADD_C
+#define BN_MP_ADD_D_C
+#define BN_MP_ADDMOD_C
+#define BN_MP_AND_C
+#define BN_MP_CLAMP_C
+#define BN_MP_CLEAR_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_CMP_C
+#define BN_MP_CMP_D_C
+#define BN_MP_CMP_MAG_C
+#define BN_MP_CNT_LSB_C
+#define BN_MP_COPY_C
+#define BN_MP_COUNT_BITS_C
+#define BN_MP_DIV_C
+#define BN_MP_DIV_2_C
+#define BN_MP_DIV_2D_C
+#define BN_MP_DIV_3_C
+#define BN_MP_DIV_D_C
+#define BN_MP_DR_IS_MODULUS_C
+#define BN_MP_DR_REDUCE_C
+#define BN_MP_DR_SETUP_C
+#define BN_MP_EXCH_C
+#define BN_MP_EXPT_D_C
+#define BN_MP_EXPTMOD_C
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_EXTEUCLID_C
+#define BN_MP_FREAD_C
+#define BN_MP_FWRITE_C
+#define BN_MP_GCD_C
+#define BN_MP_GET_INT_C
+#define BN_MP_GROW_C
+#define BN_MP_INIT_C
+#define BN_MP_INIT_COPY_C
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_INIT_SET_C
+#define BN_MP_INIT_SET_INT_C
+#define BN_MP_INIT_SIZE_C
+#define BN_MP_INVMOD_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_MP_IS_SQUARE_C
+#define BN_MP_JACOBI_C
+#define BN_MP_KARATSUBA_MUL_C
+#define BN_MP_KARATSUBA_SQR_C
+#define BN_MP_LCM_C
+#define BN_MP_LSHD_C
+#define BN_MP_MOD_C
+#define BN_MP_MOD_2D_C
+#define BN_MP_MOD_D_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_MP_MUL_C
+#define BN_MP_MUL_2_C
+#define BN_MP_MUL_2D_C
+#define BN_MP_MUL_D_C
+#define BN_MP_MULMOD_C
+#define BN_MP_N_ROOT_C
+#define BN_MP_NEG_C
+#define BN_MP_OR_C
+#define BN_MP_PRIME_FERMAT_C
+#define BN_MP_PRIME_IS_DIVISIBLE_C
+#define BN_MP_PRIME_IS_PRIME_C
+#define BN_MP_PRIME_MILLER_RABIN_C
+#define BN_MP_PRIME_NEXT_PRIME_C
+#define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+#define BN_MP_PRIME_RANDOM_EX_C
+#define BN_MP_RADIX_SIZE_C
+#define BN_MP_RADIX_SMAP_C
+#define BN_MP_RAND_C
+#define BN_MP_READ_RADIX_C
+#define BN_MP_READ_SIGNED_BIN_C
+#define BN_MP_READ_UNSIGNED_BIN_C
+#define BN_MP_REDUCE_C
+#define BN_MP_REDUCE_2K_C
+#define BN_MP_REDUCE_2K_L_C
+#define BN_MP_REDUCE_2K_SETUP_C
+#define BN_MP_REDUCE_2K_SETUP_L_C
+#define BN_MP_REDUCE_IS_2K_C
+#define BN_MP_REDUCE_IS_2K_L_C
+#define BN_MP_REDUCE_SETUP_C
+#define BN_MP_RSHD_C
+#define BN_MP_SET_C
+#define BN_MP_SET_INT_C
+#define BN_MP_SHRINK_C
+#define BN_MP_SIGNED_BIN_SIZE_C
+#define BN_MP_SQR_C
+#define BN_MP_SQRMOD_C
+#define BN_MP_SQRT_C
+#define BN_MP_SUB_C
+#define BN_MP_SUB_D_C
+#define BN_MP_SUBMOD_C
+#define BN_MP_TO_SIGNED_BIN_C
+#define BN_MP_TO_SIGNED_BIN_N_C
+#define BN_MP_TO_UNSIGNED_BIN_C
+#define BN_MP_TO_UNSIGNED_BIN_N_C
+#define BN_MP_TOOM_MUL_C
+#define BN_MP_TOOM_SQR_C
+#define BN_MP_TORADIX_C
+#define BN_MP_TORADIX_N_C
+#define BN_MP_UNSIGNED_BIN_SIZE_C
+#define BN_MP_XOR_C
+#define BN_MP_ZERO_C
+#define BN_PRIME_TAB_C
+#define BN_REVERSE_C
+#define BN_S_MP_ADD_C
+#define BN_S_MP_EXPTMOD_C
+#define BN_S_MP_MUL_DIGS_C
+#define BN_S_MP_MUL_HIGH_DIGS_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_SUB_C
+#define BNCORE_C
+#endif
+
+#if defined(BN_ERROR_C)
+ #define BN_MP_ERROR_TO_STRING_C
+#endif
+
+#if defined(BN_FAST_MP_INVMOD_C)
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_COPY_C
+ #define BN_MP_MOD_C
+ #define BN_MP_SET_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_ADD_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_DIGS_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_SQR_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_2EXPT_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_ABS_C)
+ #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_ADD_C)
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_ADD_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_ADDMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_AND_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CLAMP_C)
+#endif
+
+#if defined(BN_MP_CLEAR_C)
+#endif
+
+#if defined(BN_MP_CLEAR_MULTI_C)
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CMP_C)
+ #define BN_MP_CMP_MAG_C
+#endif
+
+#if defined(BN_MP_CMP_D_C)
+#endif
+
+#if defined(BN_MP_CMP_MAG_C)
+#endif
+
+#if defined(BN_MP_CNT_LSB_C)
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_COPY_C)
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_COUNT_BITS_C)
+#endif
+
+#if defined(BN_MP_DIV_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_SET_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_ABS_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SUB_C
+ #define BN_MP_ADD_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_INIT_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_2_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_DIV_2D_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_DIV_3_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_D_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_COPY_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(BN_MP_DR_REDUCE_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_DR_SETUP_C)
+#endif
+
+#if defined(BN_MP_EXCH_C)
+#endif
+
+#if defined(BN_MP_EXPT_D_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_SET_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_INVMOD_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_ABS_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_REDUCE_IS_2K_L_C
+ #define BN_S_MP_EXPTMOD_C
+ #define BN_MP_DR_IS_MODULUS_C
+ #define BN_MP_REDUCE_IS_2K_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_FAST_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MONTGOMERY_SETUP_C
+ #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_DR_SETUP_C
+ #define BN_MP_DR_REDUCE_C
+ #define BN_MP_REDUCE_2K_SETUP_C
+ #define BN_MP_REDUCE_2K_C
+ #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+ #define BN_MP_MULMOD_C
+ #define BN_MP_SET_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_EXTEUCLID_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_SET_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SUB_C
+ #define BN_MP_NEG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_FREAD_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_S_RMAP_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_CMP_D_C
+#endif
+
+#if defined(BN_MP_FWRITE_C)
+ #define BN_MP_RADIX_SIZE_C
+ #define BN_MP_TORADIX_C
+#endif
+
+#if defined(BN_MP_GCD_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ABS_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_GET_INT_C)
+#endif
+
+#if defined(BN_MP_GROW_C)
+#endif
+
+#if defined(BN_MP_INIT_C)
+#endif
+
+#if defined(BN_MP_INIT_COPY_C)
+ #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_INIT_MULTI_C)
+ #define BN_MP_ERR_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_INIT_SET_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_SET_INT_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_INT_C
+#endif
+
+#if defined(BN_MP_INIT_SIZE_C)
+ #define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_INVMOD_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ISODD_C
+ #define BN_FAST_MP_INVMOD_C
+ #define BN_MP_INVMOD_SLOW_C
+#endif
+
+#if defined(BN_MP_INVMOD_SLOW_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_SET_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_IS_SQUARE_C)
+ #define BN_MP_MOD_D_C
+ #define BN_MP_INIT_SET_INT_C
+ #define BN_MP_MOD_C
+ #define BN_MP_GET_INT_C
+ #define BN_MP_SQRT_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_JACOBI_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MOD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_MUL_C)
+ #define BN_MP_MUL_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_SUB_C
+ #define BN_MP_ADD_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_SQR_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_SQR_C
+ #define BN_MP_SUB_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_LCM_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_GCD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_DIV_C
+ #define BN_MP_MUL_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_LSHD_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_RSHD_C
+#endif
+
+#if defined(BN_MP_MOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_DIV_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_ADD_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_MOD_2D_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_COPY_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MOD_D_C)
+ #define BN_MP_DIV_D_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_SET_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_REDUCE_C)
+ #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(BN_MP_MUL_C)
+ #define BN_MP_TOOM_MUL_C
+ #define BN_MP_KARATSUBA_MUL_C
+ #define BN_FAST_S_MP_MUL_DIGS_C
+ #define BN_S_MP_MUL_C
+ #define BN_S_MP_MUL_DIGS_C
+#endif
+
+#if defined(BN_MP_MUL_2_C)
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MUL_2D_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_GROW_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MUL_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MULMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_MUL_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_N_ROOT_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+ #define BN_MP_COPY_C
+ #define BN_MP_EXPT_D_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SUB_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_NEG_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_OR_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_FERMAT_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_INIT_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_CMP_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_DIVISIBLE_C)
+ #define BN_MP_MOD_D_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_PRIME_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_PRIME_IS_DIVISIBLE_C
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+ #define BN_MP_PRIME_MILLER_RABIN_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_MILLER_RABIN_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SQRMOD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_NEXT_PRIME_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_SET_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_MOD_D_C
+ #define BN_MP_INIT_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_PRIME_MILLER_RABIN_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(BN_MP_PRIME_RANDOM_EX_C)
+ #define BN_MP_READ_UNSIGNED_BIN_C
+ #define BN_MP_PRIME_IS_PRIME_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_D_C
+#endif
+
+#if defined(BN_MP_RADIX_SIZE_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_RADIX_SMAP_C)
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_RAND_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_LSHD_C
+#endif
+
+#if defined(BN_MP_READ_RADIX_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_S_RMAP_C
+ #define BN_MP_RADIX_SMAP_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_READ_SIGNED_BIN_C)
+ #define BN_MP_READ_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_READ_UNSIGNED_BIN_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_REDUCE_C)
+ #define BN_MP_REDUCE_SETUP_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_C
+ #define BN_S_MP_MUL_HIGH_DIGS_C
+ #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #define BN_MP_MOD_2D_C
+ #define BN_S_MP_MUL_DIGS_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_SET_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CMP_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_L_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MUL_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_CLEAR_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_L_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_C)
+ #define BN_MP_REDUCE_2K_C
+ #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(BN_MP_REDUCE_SETUP_C)
+ #define BN_MP_2EXPT_C
+ #define BN_MP_DIV_C
+#endif
+
+#if defined(BN_MP_RSHD_C)
+ #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_C)
+ #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_INT_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SHRINK_C)
+#endif
+
+#if defined(BN_MP_SIGNED_BIN_SIZE_C)
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+#endif
+
+#if defined(BN_MP_SQR_C)
+ #define BN_MP_TOOM_SQR_C
+ #define BN_MP_KARATSUBA_SQR_C
+ #define BN_FAST_S_MP_SQR_C
+ #define BN_S_MP_SQR_C
+#endif
+
+#if defined(BN_MP_SQRMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_SQRT_C)
+ #define BN_MP_N_ROOT_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_DIV_C
+ #define BN_MP_ADD_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_SUB_C)
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_SUB_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SUBMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_C)
+ #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_N_C)
+ #define BN_MP_SIGNED_BIN_SIZE_C
+ #define BN_MP_TO_SIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_N_C)
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+ #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TOOM_MUL_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TOOM_SQR_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TORADIX_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_TORADIX_N_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_UNSIGNED_BIN_SIZE_C)
+ #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_XOR_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_ZERO_C)
+#endif
+
+#if defined(BN_PRIME_TAB_C)
+#endif
+
+#if defined(BN_REVERSE_C)
+#endif
+
+#if defined(BN_S_MP_ADD_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_REDUCE_SETUP_C
+ #define BN_MP_REDUCE_C
+ #define BN_MP_REDUCE_2K_SETUP_L_C
+ #define BN_MP_REDUCE_2K_L_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SET_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_C)
+ #define BN_FAST_S_MP_MUL_DIGS_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_C)
+ #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SQR_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SUB_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BNCORE_C)
+#endif
+
+#ifdef LTM3
+#define LTM_LAST
+#endif
+#include <tommath_superclass.h>
+#include <tommath_class.h>
+#else
+#define LTM_LAST
+#endif
+
+/* $Source: /cvs/libtom/libtommath/tommath_class.h,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2005/07/28 11:59:32 $ */
diff --git a/crypto/userspace/libtommath/tommath_superclass.h b/crypto/userspace/libtommath/tommath_superclass.h
new file mode 100644
index 00000000000..2fdebe6838f
--- /dev/null
+++ b/crypto/userspace/libtommath/tommath_superclass.h
@@ -0,0 +1,76 @@
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#define LTM_ALL
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+ LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+/* Works for RSA only, mpi.o is 68KiB */
+#ifdef SC_RSA_1
+ #define BN_MP_SHRINK_C
+ #define BN_MP_LCM_C
+ #define BN_MP_PRIME_RANDOM_EX_C
+ #define BN_MP_INVMOD_C
+ #define BN_MP_GCD_C
+ #define BN_MP_MOD_C
+ #define BN_MP_MULMOD_C
+ #define BN_MP_ADDMOD_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_SET_INT_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+ #define BN_MP_TO_UNSIGNED_BIN_C
+ #define BN_MP_MOD_D_C
+ #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+ #define BN_REVERSE_C
+ #define BN_PRIME_TAB_C
+
+ /* other modifiers */
+ #define BN_MP_DIV_SMALL /* Slower division, not critical */
+
+ /* here we are on the last pass so we turn things off. The functions classes are still there
+ * but we remove them specifically from the build. This also invokes tweaks in functions
+ * like removing support for even moduli, etc...
+ */
+#ifdef LTM_LAST
+ #undef BN_MP_TOOM_MUL_C
+ #undef BN_MP_TOOM_SQR_C
+ #undef BN_MP_KARATSUBA_MUL_C
+ #undef BN_MP_KARATSUBA_SQR_C
+ #undef BN_MP_REDUCE_C
+ #undef BN_MP_REDUCE_SETUP_C
+ #undef BN_MP_DR_IS_MODULUS_C
+ #undef BN_MP_DR_SETUP_C
+ #undef BN_MP_DR_REDUCE_C
+ #undef BN_MP_REDUCE_IS_2K_C
+ #undef BN_MP_REDUCE_2K_SETUP_C
+ #undef BN_MP_REDUCE_2K_C
+ #undef BN_S_MP_EXPTMOD_C
+ #undef BN_MP_DIV_3_C
+ #undef BN_S_MP_MUL_HIGH_DIGS_C
+ #undef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #undef BN_FAST_MP_INVMOD_C
+
+ /* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+ * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines]
+ * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+ * trouble.
+ */
+ #undef BN_S_MP_MUL_DIGS_C
+ #undef BN_S_MP_SQR_C
+ #undef BN_MP_MONTGOMERY_REDUCE_C
+#endif
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/tommath_superclass.h,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2005/05/14 13:29:17 $ */
diff --git a/crypto/userspace/ncr-dh.c b/crypto/userspace/ncr-dh.c
new file mode 100644
index 00000000000..f6ab53afc07
--- /dev/null
+++ b/crypto/userspace/ncr-dh.c
@@ -0,0 +1,296 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/ncr.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include <ncr-int.h>
+#include <tomcrypt.h>
+#include <ncr-dh.h>
+
+void dh_free(dh_key * key)
+{
+ mp_clear_multi(&key->p, &key->g, &key->x, NULL);
+}
+
+int dh_import_params(dh_key * key, uint8_t * p, size_t p_size, uint8_t * g,
+ size_t g_size)
+{
+ int ret;
+ int err;
+
+ if ((err =
+ mp_init_multi(&key->p, &key->g, &key->x, &key->y,
+ NULL)) != CRYPT_OK) {
+ err();
+ return -ENOMEM;
+ }
+
+ if ((err =
+ mp_read_unsigned_bin(&key->p, (unsigned char *) p,
+ p_size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ if ((err =
+ mp_read_unsigned_bin(&key->g, (unsigned char *) g,
+ g_size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ return 0;
+ fail:
+ mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL);
+
+ return ret;
+}
+
+int dh_generate_key(dh_key * key)
+{
+ void *buf;
+ int size;
+ int err, ret;
+
+ size = mp_unsigned_bin_size(&key->p);
+ if (size == 0) {
+ err();
+ return -EINVAL;
+ }
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ do {
+ get_random_bytes(buf, size);
+
+ if ((err = mp_read_unsigned_bin(&key->x, buf, size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ err = mp_mod(&key->x, &key->p, &key->x);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+ } while(mp_cmp_d(&key->x, 0) == MP_EQ || mp_cmp_d(&key->x, 1) == MP_EQ);
+
+ key->type = PK_PRIVATE;
+
+ ret = 0;
+ fail:
+ kfree(buf);
+
+ return ret;
+
+}
+
+int dh_generate_public(dh_key * public, dh_key * private)
+{
+ int err, ret;
+
+ err =
+ mp_exptmod(&private->g, &private->x, &private->p, &public->y);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ public->type = PK_PUBLIC;
+
+ ret = 0;
+ fail:
+
+ return ret;
+}
+
+int dh_export(uint8_t * out, unsigned long * outlen, int type, dh_key * key)
+{
+ unsigned long zero = 0;
+ int err;
+
+ if (out == NULL || outlen == NULL || key == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ /* can we store the static header? */
+ if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
+ return -EINVAL;
+ }
+
+ if (type != PK_PUBLIC && type != PK_PRIVATE) {
+ return -EINVAL;
+ }
+
+ /* This encoding is different from the one in original
+ * libtomcrypt. It uses a compatible encoding with gnutls
+ * and openssl
+ */
+ if (type == PK_PRIVATE) {
+ err = der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+ LTC_ASN1_INTEGER, 1UL, &key->p,
+ LTC_ASN1_INTEGER, 1UL, &key->g,
+ LTC_ASN1_INTEGER, 1UL, &key->x,
+ LTC_ASN1_EOL, 0UL, NULL);
+ } else {
+ err = mp_unsigned_bin_size(&key->y);
+ if (err > *outlen) {
+ err();
+ return -EOVERFLOW;
+ }
+
+ *outlen = err;
+
+ err = mp_to_unsigned_bin(&key->y, out);
+ }
+
+ if (err != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(err);
+ }
+
+ return 0;
+}
+
+int dh_import(const uint8_t * in, size_t inlen, dh_key * key)
+{
+ int err;
+ unsigned long zero = 0;
+
+ if (in == NULL || key == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ /* init key */
+ if (mp_init_multi
+ (&key->p, &key->g, &key->x, &key->y, NULL) != CRYPT_OK) {
+ return -ENOMEM;
+ }
+
+ /* get key type */
+ if ((err = der_decode_sequence_multi(in, inlen,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+ LTC_ASN1_INTEGER, 1UL, &key->p,
+ LTC_ASN1_INTEGER, 1UL, &key->g,
+ LTC_ASN1_INTEGER, 1UL, &key->x,
+ LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) {
+ key->type = PK_PRIVATE;
+ } else { /* public */
+ err = mp_read_unsigned_bin(&key->y, in, inlen);
+ key->type = PK_PUBLIC;
+ }
+
+ if (err != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ return 0;
+
+ LBL_ERR:
+ mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL);
+ return _ncr_tomerr(err);
+}
+
+int dh_derive_gxy(struct key_item_st* newkey, dh_key * key,
+ void* pk, size_t pk_size)
+{
+int ret, err;
+mp_int y, gxy;
+ /* newkey will be a secret key with value of g^{xy}
+ */
+
+ if (mp_init_multi(&y, &gxy, NULL) != CRYPT_OK) {
+ err();
+ return -ENOMEM;
+ }
+
+ if (key->type != PK_PRIVATE) {
+ err();
+ return -EINVAL;
+ }
+
+ if ((err=mp_read_unsigned_bin(&y, pk, pk_size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ if ((err=mp_exptmod(&y, &key->x, &key->p, &gxy))!= CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ err = mp_unsigned_bin_size(&gxy);
+ if (err > NCR_CIPHER_MAX_KEY_LEN) {
+ err();
+ ret = -EOVERFLOW;
+ goto fail;
+ }
+ newkey->key.secret.size = err;
+
+ err = mp_to_unsigned_bin(&gxy, newkey->key.secret.data);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ newkey->type = NCR_KEY_TYPE_SECRET;
+
+ ret = 0;
+fail:
+ mp_clear_multi(&y, &gxy, NULL);
+
+ return ret;
+}
+
+int ncr_pk_get_dh_size( dh_key* key)
+{
+int ret;
+ ret = mp_count_bits(&key->p);
+ if (ret <= 0) {
+ err();
+ return -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/crypto/userspace/ncr-dh.h b/crypto/userspace/ncr-dh.h
new file mode 100644
index 00000000000..183f7909154
--- /dev/null
+++ b/crypto/userspace/ncr-dh.h
@@ -0,0 +1,27 @@
+#ifndef NCR_DH_H
+# define NCR_DH_H
+
+#include <tomcrypt.h>
+
+typedef struct {
+ int type; /* PK_PRIVATE or PK_PUBLIC */
+ mp_int p;
+ mp_int g;
+ mp_int x; /* private */
+ mp_int y; /* public: y=g^x */
+} dh_key;
+
+int dh_generate_key(dh_key * key);
+int dh_import_params(dh_key * key, uint8_t* p, size_t p_size, uint8_t* g, size_t g_size);
+void dh_free(dh_key * key);
+int dh_generate_public(dh_key * public, dh_key* private);
+
+int dh_export(uint8_t *out, unsigned long *outlen, int type, dh_key *key);
+int dh_import(const uint8_t *in, size_t inlen, dh_key *key);
+
+int dh_derive_gxy(struct key_item_st* newkey, dh_key * key,
+ void* pk, size_t pk_size);
+
+int ncr_pk_get_dh_size( dh_key* key);
+
+#endif
diff --git a/crypto/userspace/ncr-int.h b/crypto/userspace/ncr-int.h
new file mode 100644
index 00000000000..21e782d4b5a
--- /dev/null
+++ b/crypto/userspace/ncr-int.h
@@ -0,0 +1,241 @@
+#ifndef NCR_INT_H
+# define NCR_INT_H
+
+#include <linux/compat.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/ncr.h>
+#include <asm/atomic.h>
+#include "cryptodev_int.h"
+#include <ncr-pk.h>
+#include <ncr-dh.h>
+
+#define KEY_DATA_MAX_SIZE 3*1024
+#define NCR_CIPHER_MAX_KEY_LEN 1024
+
+#define err() printk(KERN_DEBUG"ncr: %s: %s: %d\n", __FILE__, __func__, __LINE__)
+
+struct nlattr;
+struct ncr_out;
+
+// Not all known algorithms - only for quick internal identification. Note
+// that more than one struct algo_properties_st may share the same enum value!
+typedef enum {
+ NCR_ALG_NONE,
+ NCR_ALG_NULL,
+
+ NCR_ALG_3DES_CBC,
+ NCR_ALG_3DES_ECB,
+
+ NCR_ALG_AES_ECB,
+ NCR_ALG_AES_CBC,
+ NCR_ALG_AES_CTR,
+
+ NCR_ALG_CAMELIA_ECB,
+ NCR_ALG_CAMELIA_CBC,
+ NCR_ALG_CAMELIA_CTR,
+
+ NCR_ALG_MD5=200,
+ NCR_ALG_SHA1,
+ NCR_ALG_SHA2_224,
+ NCR_ALG_SHA2_256,
+ NCR_ALG_SHA2_384,
+ NCR_ALG_SHA2_512,
+
+ NCR_ALG_RSA=600,
+ NCR_ALG_DSA,
+ NCR_ALG_DH,
+} ncr_algorithm_t;
+
+struct algo_oid_st {
+ oid_st oid;
+ int key_size;
+};
+
+struct algo_properties_st {
+ ncr_algorithm_t algo;
+ const char *kstr;
+ size_t kstr_len;
+ unsigned needs_iv:1;
+ unsigned is_hmac:1;
+ unsigned can_sign:1;
+ unsigned can_digest:1;
+ unsigned can_encrypt:1;
+ unsigned can_kx:1; /* key exchange */
+ unsigned is_symmetric:1;
+ unsigned is_pk:1;
+ unsigned has_transparent_hash:1;
+ int digest_size;
+ /* NCR_KEY_TYPE_SECRET if for a secret key algorithm or MAC,
+ * NCR_KEY_TYPE_PUBLIC for a public key algorithm.
+ */
+ ncr_key_type_t key_type;
+ const struct algo_oid_st *oids;
+};
+
+struct key_item_st {
+ /* This object is also not protected from concurrent access.
+ */
+ ncr_key_type_t type;
+ unsigned int flags;
+ const struct algo_properties_st *algorithm; /* non-NULL for public/private keys */
+ uint8_t key_id[MAX_KEY_ID_SIZE];
+ size_t key_id_size;
+
+ union {
+ struct {
+ uint8_t data[NCR_CIPHER_MAX_KEY_LEN];
+ size_t size;
+ } secret;
+ union {
+ rsa_key rsa;
+ dsa_key dsa;
+ dh_key dh;
+ } pk;
+ } key;
+
+ atomic_t refcnt;
+ atomic_t writer;
+
+ /* owner. The one charged with this */
+ uid_t uid;
+ pid_t pid;
+
+ int context_id; /* Only for auditing */
+ ncr_key_t desc;
+};
+
+/* all the data associated with the open descriptor
+ * are here.
+ */
+struct ncr_lists {
+ int id; /* Used only for auditing */
+
+ struct mutex key_idr_mutex;
+ struct idr key_idr;
+
+ /* sessions */
+ struct mutex session_idr_mutex;
+ struct idr session_idr;
+};
+
+struct ncr_lists *ncr_init_lists(void);
+void ncr_deinit_lists(struct ncr_lists *lst);
+
+long ncr_ioctl(struct ncr_lists *lst, unsigned int cmd, unsigned long arg);
+long ncr_compat_ioctl(struct ncr_lists *lst, unsigned int cmd,
+ unsigned long arg);
+
+/* key derivation */
+int ncr_key_derive(struct ncr_lists *lst, const struct ncr_key_derive *data,
+ struct nlattr *tb[]);
+
+void ncr_key_clear(struct key_item_st* item);
+int ncr_key_update_flags(struct key_item_st *item, const struct nlattr *nla);
+
+/* key handling */
+int ncr_key_init(struct ncr_lists *lst);
+int ncr_key_deinit(struct ncr_lists *lst, ncr_key_t desc);
+int ncr_key_export(struct ncr_lists *lst, const struct ncr_key_export *data,
+ struct nlattr *tb[]);
+int ncr_key_import(struct ncr_lists *lst, const struct ncr_key_import *data,
+ struct nlattr *tb[]);
+void ncr_key_list_deinit(struct ncr_lists *lst);
+int ncr_key_generate(struct ncr_lists *lst, const struct ncr_key_generate *gen,
+ struct nlattr *tb[]);
+int ncr_key_get_info(struct ncr_lists *lst, struct ncr_out *out,
+ const struct ncr_key_get_info *info, struct nlattr *tb[]);
+
+int ncr_key_generate_pair(struct ncr_lists *lst,
+ const struct ncr_key_generate_pair *gen,
+ struct nlattr *tb[]);
+int ncr_key_get_public(struct ncr_lists *lst, void __user* arg);
+
+int ncr_key_item_get_read(struct key_item_st**st, struct ncr_lists *lst,
+ ncr_key_t desc);
+/* get key item for writing */
+int ncr_key_item_get_write( struct key_item_st** st,
+ struct ncr_lists *lst, ncr_key_t desc);
+void _ncr_key_item_put( struct key_item_st* item);
+
+typedef enum {
+ LIMIT_TYPE_KEY,
+ NUM_LIMIT_TYPES
+} limits_type_t;
+
+void ncr_limits_remove(uid_t uid, pid_t pid, limits_type_t type);
+int ncr_limits_add_and_check(uid_t uid, pid_t pid, limits_type_t type);
+void ncr_limits_init(void);
+void ncr_limits_deinit(void);
+
+int ncr_key_wrap(struct ncr_lists *lst, const struct ncr_key_wrap *wrap,
+ struct nlattr *tb[]);
+int ncr_key_unwrap(struct ncr_lists *lst, const struct ncr_key_unwrap *wrap,
+ struct nlattr *tb[]);
+int ncr_key_storage_wrap(struct ncr_lists *lst,
+ const struct ncr_key_storage_wrap *wrap,
+ struct nlattr *tb[]);
+int ncr_key_storage_unwrap(struct ncr_lists *lst,
+ const struct ncr_key_storage_unwrap *wrap,
+ struct nlattr *tb[]);
+
+/* sessions */
+void ncr_sessions_list_deinit(struct ncr_lists *lst);
+
+int ncr_session_init(struct ncr_lists *lists,
+ const struct ncr_session_init *session,
+ struct nlattr *tb[]);
+int ncr_session_update(struct ncr_lists *lists,
+ const struct ncr_session_update *op, struct nlattr *tb[],
+ int compat);
+int ncr_session_final(struct ncr_lists *lists,
+ const struct ncr_session_final *op, struct nlattr *tb[],
+ int compat);
+int ncr_session_once(struct ncr_lists *lists,
+ const struct ncr_session_once *once, struct nlattr *tb[],
+ int compat);
+
+/* master key */
+extern struct key_item_st master_key;
+
+void ncr_master_key_reset(void);
+
+/* storage */
+int key_from_storage_data(struct key_item_st* key, const void* data, size_t data_size);
+int key_to_storage_data( uint8_t** data, size_t * data_size, const struct key_item_st *key);
+
+
+/* misc helper macros */
+
+const struct algo_properties_st *_ncr_algo_to_properties(ncr_algorithm_t algo);
+const struct algo_properties_st *_ncr_nla_to_properties(const struct nlattr *nla);
+const char *ncr_algorithm_name(const struct algo_properties_st *algo);
+int _ncr_key_get_sec_level(struct key_item_st* item);
+const struct algo_properties_st *_ncr_oid_to_properties(oid_st* oid);
+const oid_st* _ncr_properties_to_oid(const struct algo_properties_st * prop, int key_size);
+
+/* CONFIG_COMPAT handling */
+
+#ifdef CONFIG_COMPAT
+struct compat_ncr_session_input_data {
+ compat_uptr_t data;
+ compat_size_t data_size;
+};
+
+struct compat_ncr_session_output_buffer {
+ compat_uptr_t buffer;
+ compat_size_t buffer_size;
+ compat_uptr_t result_size_ptr;
+};
+#endif
+
+int ncr_session_input_data_from_nla(struct ncr_session_input_data *dest,
+ const struct nlattr *nla, int compat);
+
+int ncr_session_output_buffer_from_nla(struct ncr_session_output_buffer *dest,
+ const struct nlattr *nla, int compat);
+
+int ncr_session_output_buffer_set_size(const struct ncr_session_output_buffer *dest,
+ size_t size, int compat);
+
+#endif
diff --git a/crypto/userspace/ncr-key-storage.c b/crypto/userspace/ncr-key-storage.c
new file mode 100644
index 00000000000..512401828f4
--- /dev/null
+++ b/crypto/userspace/ncr-key-storage.c
@@ -0,0 +1,136 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/ncr.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include "ncr-int.h"
+#include "cryptodev_int.h"
+
+struct packed_key {
+ uint32_t version;
+ uint8_t type;
+ uint32_t flags;
+ uint32_t algorithm;
+ uint8_t key_id[MAX_KEY_ID_SIZE];
+ uint8_t key_id_size;
+
+ uint8_t raw[KEY_DATA_MAX_SIZE];
+ uint32_t raw_size;
+} __attribute__((__packed__));
+
+#define THIS_VERSION 2
+
+int key_to_storage_data( uint8_t** sdata, size_t * sdata_size, const struct key_item_st *key)
+{
+ struct packed_key * pkey;
+ int ret;
+
+ pkey = kmalloc(sizeof(*pkey), GFP_KERNEL);
+ if (pkey == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ pkey->version = THIS_VERSION;
+ pkey->type = key->type;
+ pkey->flags = key->flags;
+
+ pkey->algorithm = key->algorithm->algo;
+
+ pkey->key_id_size = key->key_id_size;
+ memcpy(pkey->key_id, key->key_id, key->key_id_size);
+
+ if (key->type == NCR_KEY_TYPE_SECRET) {
+ pkey->raw_size = key->key.secret.size;
+ memcpy(pkey->raw, key->key.secret.data, pkey->raw_size);
+ } else if (key->type == NCR_KEY_TYPE_PRIVATE || key->type == NCR_KEY_TYPE_PUBLIC) {
+ pkey->raw_size = sizeof(pkey->raw);
+ ret = ncr_pk_pack( key, pkey->raw, &pkey->raw_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ } else {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ *sdata = (void*)pkey;
+ *sdata_size = sizeof(*pkey);
+
+ return 0;
+fail:
+ kfree(pkey);
+
+ return ret;
+}
+
+int key_from_storage_data(struct key_item_st* key, const void* data, size_t data_size)
+{
+ const struct packed_key * pkey = data;
+ int ret;
+
+ if (data_size != sizeof(*pkey) || pkey->version != THIS_VERSION
+ || pkey->key_id_size > MAX_KEY_ID_SIZE) {
+ err();
+ return -EINVAL;
+ }
+
+ key->type = pkey->type;
+ key->flags = pkey->flags;
+
+ key->algorithm = _ncr_algo_to_properties(pkey->algorithm);
+ if (key->algorithm == NULL) {
+ err();
+ return -EINVAL;
+ }
+ key->key_id_size = pkey->key_id_size;
+ memcpy(key->key_id, pkey->key_id, pkey->key_id_size);
+
+ if (key->type == NCR_KEY_TYPE_SECRET) {
+ if (pkey->raw_size > NCR_CIPHER_MAX_KEY_LEN) {
+ err();
+ return -EINVAL;
+ }
+ key->key.secret.size = pkey->raw_size;
+ memcpy(key->key.secret.data, pkey->raw, pkey->raw_size);
+ } else if (key->type == NCR_KEY_TYPE_PUBLIC
+ || key->type == NCR_KEY_TYPE_PRIVATE) {
+ ret = ncr_pk_unpack( key, pkey->raw, pkey->raw_size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ } else {
+ err();
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/crypto/userspace/ncr-key-wrap.c b/crypto/userspace/ncr-key-wrap.c
new file mode 100644
index 00000000000..ce061312dc0
--- /dev/null
+++ b/crypto/userspace/ncr-key-wrap.c
@@ -0,0 +1,1118 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/audit.h>
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/ncr.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/random.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include <net/netlink.h>
+#include "ncr-int.h"
+#include "cryptodev_int.h"
+
+#define KEY_WRAP_VERSION 0
+
+/* To be further checked. If the current implemented key wrapping mechanism
+ * has no issues, it might be possible to relax the requirement for
+ * privileged key wrapping.
+ */
+#define KEY_WRAP_IS_PRIVILEGED
+
+typedef uint8_t val64_t[8];
+
+static const val64_t initA = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6";
+
+static int key_to_packed_data( uint8_t** sdata, size_t * sdata_size, const struct key_item_st *key);
+static int key_from_packed_data(struct nlattr *tb[], struct key_item_st* key,
+ const void* data, size_t data_size);
+
+
+static void val64_xor( val64_t val, uint32_t x)
+{
+ val[7] ^= x & 0xff;
+ val[6] ^= (x >> 8) & 0xff;
+ val[5] ^= (x >> 16) & 0xff;
+ val[4] ^= (x >> 24) & 0xff;
+}
+
+static int rfc3394_wrap(val64_t *R, unsigned int n, struct cipher_data* ctx,
+ uint8_t* output, size_t *output_size, const uint8_t iv[8])
+{
+val64_t A;
+uint8_t aes_block[16];
+int i,j;
+
+ if (*output_size < (n+1)*8) {
+ err();
+ return -ERANGE;
+ }
+
+ memcpy(A, iv, 8);
+
+ for (i=0;i<6*n;i++) {
+ memcpy(aes_block, A, 8);
+ memcpy(&aes_block[8], R[0], 8);
+
+ _cryptodev_cipher_encrypt(ctx, aes_block, sizeof(aes_block),
+ aes_block, sizeof(aes_block));
+
+ memcpy(A, aes_block, 8); /* A = MSB64(AES(A^{t-1}|R_{1}^{t-1})) */
+ val64_xor(A, i+1); /* A ^= t */
+
+ for (j=0;j<n-1;j++)
+ memcpy(R[j], R[j+1], sizeof(R[j]));
+ memcpy(R[n-1], &aes_block[8], 8); /* R[n-1] = LSB64(AES(A^{t-1}|R_{1}^{t-1})) */
+ }
+
+ memcpy(output, A, sizeof(A));
+ for (j=0;j<n;j++)
+ memcpy(&output[(j+1)*8], R[j], 8);
+ *output_size = (n+1)*8;
+
+ return 0;
+}
+
+static int rfc3394_unwrap(const uint8_t *wrapped_key, val64_t R[], unsigned int n, val64_t A, struct cipher_data *ctx)
+{
+ int i, j;
+ uint8_t aes_block[16];
+
+ memcpy(A, wrapped_key, 8); /* A = C[0] */
+ for (i=0;i<n;i++)
+ memcpy(R[i], &wrapped_key[(i+1)*8], 8);
+
+ for (i=(6*n)-1;i>=0;i--) {
+ val64_xor(A, i+1);
+
+ memcpy(aes_block, A, 8);
+ memcpy(&aes_block[8], R[n-1], 8);
+
+ _cryptodev_cipher_decrypt(ctx, aes_block, sizeof(aes_block),
+ aes_block, sizeof(aes_block));
+
+ memcpy(A, aes_block, 8);
+
+ for (j=n-1;j>=1;j--)
+ memcpy(R[j], R[j-1], sizeof(R[j]));
+
+ memcpy(R[0], &aes_block[8], 8);
+ }
+
+ return 0;
+}
+
+#define RFC5649_IV "\xA6\x59\x59\xA6"
+static int _wrap_aes_rfc5649(void* kdata, size_t kdata_size, struct key_item_st* kek,
+ void* output, size_t* output_size, const void* _iv, size_t iv_size)
+{
+size_t n;
+int i, ret;
+struct cipher_data ctx;
+uint8_t iv[8];
+val64_t *R = NULL;
+
+ if (iv_size != 4) {
+ memcpy(iv, RFC5649_IV, 4);
+ } else {
+ memcpy(iv, _iv, 4);
+ }
+ iv_size = 8;
+ iv[4] = (kdata_size >> 24) & 0xff;
+ iv[5] = (kdata_size >> 16) & 0xff;
+ iv[6] = (kdata_size >> 8) & 0xff;
+ iv[7] = (kdata_size) & 0xff;
+
+ n = (kdata_size+7)/8;
+ if (n==1) { /* unimplemented */
+ err();
+ return -EINVAL;
+ }
+
+ ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ R = kmalloc(n * sizeof (*R), GFP_KERNEL);
+ if (R == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* R = P */
+ for (i=0;i<kdata_size;i++) {
+ R[i/8][i%8] = ((uint8_t*)kdata)[i];
+ }
+
+ for (;i<n*8;i++) {
+ R[i/8][i%8] = 0;
+ }
+
+ ret = rfc3394_wrap( R, n, &ctx, output, output_size, iv);
+ if (ret < 0) {
+ err();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ kfree(R);
+ cryptodev_cipher_deinit(&ctx);
+
+ return ret;
+}
+
+static int _unwrap_aes_rfc5649(void* kdata, size_t *kdata_size, struct key_item_st* kek,
+ const void *wrapped_key, size_t wrapped_key_size, const void* _iv, size_t iv_size)
+{
+size_t n;
+int i, ret;
+struct cipher_data ctx;
+uint8_t iv[4];
+size_t size;
+val64_t *R = NULL, A;
+
+ if (iv_size != 4) {
+ memcpy(iv, RFC5649_IV, 4);
+ } else {
+ memcpy(iv, _iv, 4);
+ }
+ iv_size = 4;
+
+ ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ if (wrapped_key_size % 8 != 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ n = wrapped_key_size/8 - 1;
+
+ if (*kdata_size < (n-1)*8) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ R = kmalloc(n * sizeof (*R), GFP_KERNEL);
+ if (R == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = rfc3394_unwrap(wrapped_key, R, n, A, &ctx);
+ if (ret < 0) {
+ err();
+ goto cleanup;
+ }
+
+ if (memcmp(A, iv, 4)!= 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ size = (A[4] << 24) | (A[5] << 16) | (A[6] << 8) | A[7];
+ if (size > n*8 || size < (n-1)*8 || *kdata_size < size) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ memset(kdata, 0, size);
+ *kdata_size = size;
+ for (i=0;i<size;i++) {
+ ((uint8_t*)kdata)[i] = R[i/8][i%8];
+ }
+
+ ret = 0;
+
+cleanup:
+ kfree(R);
+ cryptodev_cipher_deinit(&ctx);
+
+ return ret;
+}
+
+
+static int wrap_aes_rfc5649(struct key_item_st* tobewrapped, struct key_item_st *kek,
+ void* output, size_t* output_size, const void* iv, size_t iv_size)
+{
+int ret;
+uint8_t* sdata = NULL;
+size_t sdata_size = 0;
+
+ ret = key_to_packed_data(&sdata, &sdata_size, tobewrapped);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ ret = _wrap_aes_rfc5649(sdata, sdata_size,
+ kek, output, output_size, iv, iv_size);
+
+ kfree(sdata);
+
+ return ret;
+}
+
+static int unwrap_aes_rfc5649(struct key_item_st* output, struct key_item_st *kek,
+ void *wrapped, size_t wrapped_size, struct nlattr *tb[])
+{
+const struct nlattr *nla;
+int ret, iv_size;
+void * sdata;
+size_t sdata_size = KEY_DATA_MAX_SIZE;
+const uint8_t *iv;
+
+ sdata = kmalloc(sdata_size, GFP_KERNEL);
+ if (sdata == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ nla = tb[NCR_ATTR_IV];
+ if (nla != NULL) {
+ iv = nla_data(nla);
+ iv_size = nla_len(nla);
+ } else {
+ iv = NULL;
+ iv_size = 0;
+ }
+
+ ret = _unwrap_aes_rfc5649(sdata, &sdata_size, kek,
+ wrapped, wrapped_size, iv, iv_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = key_from_packed_data(tb, output, sdata, sdata_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ kfree(sdata);
+ return ret;
+
+}
+
+
+/* Wraps using the RFC3394 way.
+ */
+static int wrap_aes_rfc3394(struct key_item_st* tobewrapped, struct key_item_st *kek,
+ void* output, size_t *output_size, const void* iv, size_t iv_size)
+{
+size_t key_size, n;
+uint8_t *raw_key;
+int i, ret;
+struct cipher_data ctx;
+val64_t *R = NULL;
+
+ if (tobewrapped->type != NCR_KEY_TYPE_SECRET) {
+ err();
+ return -EINVAL;
+ }
+
+ if (iv_size < sizeof(initA)) {
+ iv_size = sizeof(initA);
+ iv = initA;
+ }
+
+ ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ raw_key = tobewrapped->key.secret.data;
+ key_size = tobewrapped->key.secret.size;
+
+ if (key_size % 8 != 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ n = key_size/8;
+
+
+ R = kmalloc(sizeof(*R)*n, GFP_KERNEL);
+ if (R == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* R = P */
+ for (i=0;i<n;i++) {
+ memcpy(R[i], &raw_key[i*8], 8);
+ }
+
+ ret = rfc3394_wrap( R, n, &ctx, output, output_size, iv);
+ if (ret < 0) {
+ err();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ kfree(R);
+ cryptodev_cipher_deinit(&ctx);
+
+ return ret;
+}
+
+#if 0
+/* for debugging */
+void print_val64(char* str, val64_t val)
+{
+ int i;
+ printk("%s: ",str);
+ for (i=0;i<8;i++)
+ printk("%.2x", val[i]);
+ printk("\n");
+
+}
+#endif
+
+static int unwrap_aes_rfc3394(struct key_item_st* output, struct key_item_st *kek,
+ void* wrapped_key, size_t wrapped_key_size,
+ struct nlattr *tb[])
+{
+const struct nlattr *nla;
+size_t n;
+val64_t A;
+int i, ret;
+struct cipher_data ctx;
+val64_t * R = NULL;
+int iv_size;
+const uint8_t *iv;
+
+ nla = tb[NCR_ATTR_IV];
+ if (nla != NULL) {
+ iv = nla_data(nla);
+ iv_size = nla_len(nla);
+ } else
+ iv_size = 0;
+ if (iv_size < sizeof(initA)) {
+ iv_size = sizeof(initA);
+ iv = initA;
+ }
+
+ ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ output->type = NCR_KEY_TYPE_SECRET;
+
+ if (wrapped_key_size % 8 != 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ n = wrapped_key_size/8 - 1;
+
+ if (NCR_CIPHER_MAX_KEY_LEN < (n-1)*8) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ R = kmalloc(sizeof(*R)*n, GFP_KERNEL);
+ if (R == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = rfc3394_unwrap(wrapped_key, R, n, A, &ctx);
+ if (ret < 0) {
+ err();
+ goto cleanup;
+ }
+
+ if (memcmp(A, iv, 8)!= 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = ncr_key_update_flags(output, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret != 0) {
+ err();
+ goto cleanup;
+ }
+
+ memset(&output->key, 0, sizeof(output->key));
+ for (i=0;i<n;i++) {
+ memcpy(&output->key.secret.data[i*8], R[i], sizeof(R[i]));
+ }
+ output->key.secret.size = n*8;
+ output->type = NCR_KEY_TYPE_SECRET;
+
+ ret = 0;
+
+cleanup:
+ kfree(R);
+ cryptodev_cipher_deinit(&ctx);
+
+ return ret;
+}
+
+/* will check if the kek is of equal or higher security level than
+ * wkey. To prevent encrypting a 256 bit key with an 128 bit one.
+ */
+static int check_key_level(struct key_item_st* kek, struct key_item_st* wkey)
+{
+int kek_level, wkey_level;
+
+ /* allow wrapping of public keys with any key */
+ if (wkey->type == NCR_KEY_TYPE_PUBLIC)
+ return 0;
+
+ kek_level = _ncr_key_get_sec_level(kek);
+ if (kek_level < 0) {
+ err();
+ return kek_level;
+ }
+
+ wkey_level = _ncr_key_get_sec_level(wkey);
+ if (wkey_level < 0) {
+ err();
+ return wkey_level;
+ }
+
+ if (wkey_level > kek_level) {
+ err();
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static const char *ncr_wrap_name(struct nlattr *tb[])
+{
+ static const char *const known_algorithms[] = {
+ NCR_WALG_AES_RFC3394, NCR_WALG_AES_RFC5649
+ };
+
+ size_t i;
+ const struct nlattr *nla;
+
+ /* Only allow known algorithms to prevent log injection. Return the
+ static string, not nla_data(), which will go away before the ioctl()
+ handler returns. */
+ nla = tb[NCR_ATTR_WRAPPING_ALGORITHM];
+ for (i = 0; i < ARRAY_SIZE(known_algorithms); i++) {
+ if (nla_strcmp(nla, known_algorithms[i]) == 0)
+ return known_algorithms[i];
+ }
+ return "unknown";
+}
+
+int ncr_key_wrap(struct ncr_lists *lst, const struct ncr_key_wrap *wrap,
+ struct nlattr *tb[])
+{
+const struct nlattr *nla;
+struct key_item_st* wkey = NULL;
+struct key_item_st* key = NULL;
+void* data = NULL;
+const void *iv;
+size_t data_size, iv_size;
+int ret;
+
+#ifdef KEY_WRAP_IS_PRIVILEGED
+ if (current_euid() != 0) {
+ err();
+ return -EPERM;
+ }
+#endif
+
+ if (wrap->buffer_size < 0) {
+ err();
+ return -EINVAL;
+ }
+
+ ret = ncr_key_item_get_read(&wkey, lst, wrap->source_key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ if (!(wkey->flags & NCR_KEY_FLAG_WRAPPABLE)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ ret = ncr_key_item_get_read(&key, lst, wrap->wrapping_key);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ if (!(key->flags & NCR_KEY_FLAG_WRAPPING)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ ret = check_key_level(key, wkey);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ data_size = wrap->buffer_size;
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (data == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ nla = tb[NCR_ATTR_IV];
+ if (nla != NULL) {
+ iv = nla_data(nla);
+ iv_size = nla_len(nla);
+ } else {
+ iv = NULL;
+ iv_size = 0;
+ }
+
+ nla = tb[NCR_ATTR_WRAPPING_ALGORITHM];
+ if (nla == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (nla_strcmp(nla, NCR_WALG_AES_RFC3394) == 0)
+ ret = wrap_aes_rfc3394(wkey, key, data, &data_size, iv,
+ iv_size);
+ else if (nla_strcmp(nla, NCR_WALG_AES_RFC5649) == 0)
+ ret = wrap_aes_rfc5649(wkey, key, data, &data_size, iv,
+ iv_size);
+ else {
+ err();
+ ret = -EINVAL;
+ }
+
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = copy_to_user(wrap->buffer, data, data_size);
+ if (unlikely(ret)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ ret = data_size;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_WRAP, lst->id, -1, NULL,
+ ncr_wrap_name(tb), wrap->wrapping_key,
+ key != NULL ? key->key_id : NULL,
+ key != NULL ? key->key_id_size : 0,
+ wrap->source_key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (key != NULL) _ncr_key_item_put(key);
+ kfree(data);
+
+ return ret;
+}
+
+/* Unwraps keys. All keys unwrapped are not accessible by
+ * userspace.
+ */
+int ncr_key_unwrap(struct ncr_lists *lst, const struct ncr_key_unwrap *wrap,
+ struct nlattr *tb[])
+{
+const struct nlattr *nla;
+struct key_item_st* wkey = NULL;
+struct key_item_st* key = NULL;
+void* data = NULL;
+size_t data_size;
+int ret;
+
+#ifdef KEY_WRAP_IS_PRIVILEGED
+ if (current_euid() != 0) {
+ err();
+ return -EPERM;
+ }
+#endif
+
+ ret = ncr_key_item_get_write(&wkey, lst, wrap->dest_key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ ret = ncr_key_item_get_read(&key, lst, wrap->wrapping_key);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ if (!(key->flags & NCR_KEY_FLAG_UNWRAPPING)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ data_size = wrap->data_size;
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (data == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (unlikely(copy_from_user(data, wrap->data, data_size))) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ ncr_key_clear(wkey);
+
+ nla = tb[NCR_ATTR_WRAPPING_ALGORITHM];
+ if (nla == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (nla_strcmp(nla, NCR_WALG_AES_RFC3394) == 0)
+ ret = unwrap_aes_rfc3394(wkey, key, data, data_size, tb);
+ else if (nla_strcmp(nla, NCR_WALG_AES_RFC5649) == 0)
+ ret = unwrap_aes_rfc5649(wkey, key, data, data_size, tb);
+ else {
+ err();
+ ret = -EINVAL;
+ }
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_UNWRAP, lst->id, -1, NULL,
+ ncr_wrap_name(tb), wrap->wrapping_key,
+ key != NULL ? key->key_id : NULL,
+ key != NULL ? key->key_id_size : 0, wrap->dest_key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (key != NULL) _ncr_key_item_put(key);
+ if (data != NULL) kfree(data);
+
+ return ret;
+}
+
+int ncr_key_storage_wrap(struct ncr_lists *lst,
+ const struct ncr_key_storage_wrap *wrap,
+ struct nlattr *tb[])
+{
+struct key_item_st* wkey = NULL;
+void* data = NULL;
+size_t data_size;
+uint8_t * sdata = NULL;
+size_t sdata_size = 0;
+int ret;
+
+ if (master_key.type != NCR_KEY_TYPE_SECRET) {
+ err();
+ return -ENOKEY;
+ }
+
+ if (wrap->buffer_size < 0) {
+ err();
+ return -EINVAL;
+ }
+
+ ret = ncr_key_item_get_read(&wkey, lst, wrap->key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ data_size = wrap->buffer_size;
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (data == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ ret = key_to_storage_data(&sdata, &sdata_size, wkey);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = _wrap_aes_rfc5649(sdata, sdata_size, &master_key, data, &data_size, NULL, 0);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = copy_to_user(wrap->buffer, data, data_size);
+ if (unlikely(ret)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ ret = data_size;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_WRAP, lst->id, -1, NULL, NULL,
+ -1, NULL, 0, wrap->key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (data != NULL) kfree(data);
+ if (sdata != NULL) kfree(sdata);
+
+ return ret;
+}
+
+int ncr_key_storage_unwrap(struct ncr_lists *lst,
+ const struct ncr_key_storage_unwrap *wrap,
+ struct nlattr *tb[])
+{
+struct key_item_st* wkey = NULL;
+void* data = NULL;
+uint8_t * sdata = NULL;
+size_t sdata_size = 0, data_size;
+int ret;
+
+ if (master_key.type != NCR_KEY_TYPE_SECRET) {
+ err();
+ return -ENOKEY;
+ }
+
+ ret = ncr_key_item_get_write(&wkey, lst, wrap->key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ data_size = wrap->data_size;
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (data == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (unlikely(copy_from_user(data, wrap->data, data_size))) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ sdata_size = data_size;
+ sdata = kmalloc(sdata_size, GFP_KERNEL);
+ if (sdata == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ ret = _unwrap_aes_rfc5649(sdata, &sdata_size, &master_key, data, data_size, NULL, 0);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ncr_key_clear(wkey);
+
+ ret = key_from_storage_data(wkey, sdata, sdata_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_UNWRAP, lst->id, -1, NULL, NULL,
+ -1, NULL, 0, wrap->key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (data != NULL) kfree(data);
+ if (sdata != NULL) kfree(sdata);
+
+ return ret;
+}
+
+#define DER_KEY_MAX_SIZE (KEY_DATA_MAX_SIZE+16)
+
+/* Packed data are DER encoded:
+ * PackedData ::= SEQUENCE {
+ * version INTEGER { v1(0) }
+ * algorithm OBJECT IDENTIFIER,
+ * type INTEGER { secret_key(0), public(1), private(2) },
+ * data OCTET STRING
+ * }
+ *
+ * This allows distinguishing types of wrapped keys.
+ */
+static int key_to_packed_data( uint8_t** sdata, size_t * sdata_size, const struct key_item_st *key)
+{
+ uint8_t * pkey = NULL;
+ uint8_t * derkey = NULL;
+ uint32_t pkey_size;
+ int ret, err;
+ unsigned long version = KEY_WRAP_VERSION;
+ unsigned long type;
+ unsigned long derlen;
+ const oid_st* oid;
+
+ *sdata_size = KEY_DATA_MAX_SIZE;
+ pkey = kmalloc(*sdata_size, GFP_KERNEL);
+ if (pkey == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ derlen = DER_KEY_MAX_SIZE;
+ derkey = kmalloc(derlen, GFP_KERNEL);
+ if (derkey == NULL) {
+ err();
+ goto fail;
+ }
+
+ if (key->type == NCR_KEY_TYPE_SECRET) {
+ memcpy(pkey, key->key.secret.data, key->key.secret.size);
+ pkey_size = key->key.secret.size;
+
+ type = 0;
+ } else if (key->type == NCR_KEY_TYPE_PRIVATE || key->type == NCR_KEY_TYPE_PUBLIC) {
+ pkey_size = *sdata_size;
+ ret = ncr_pk_pack( key, pkey, &pkey_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ if (key->type == NCR_KEY_TYPE_PUBLIC)
+ type = 1;
+ else type = 2;
+ } else {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ oid = _ncr_properties_to_oid(key->algorithm, pkey_size);
+ if (oid == NULL) {
+ err();
+ ret = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ err = der_encode_sequence_multi(derkey, &derlen,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+ LTC_ASN1_OBJECT_IDENTIFIER, oid->OIDlen, oid->OID,
+ LTC_ASN1_SHORT_INTEGER, 1UL, &type,
+ LTC_ASN1_OCTET_STRING, (unsigned long)pkey_size, pkey,
+ LTC_ASN1_EOL, 0UL, NULL);
+
+ kfree(pkey);
+
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ *sdata = (void*)derkey;
+ *sdata_size = derlen;
+
+ return 0;
+fail:
+ kfree(pkey);
+ kfree(derkey);
+
+ return ret;
+}
+
+inline static int packed_type_to_key_type(unsigned long type, struct key_item_st* key)
+{
+ switch(type) {
+ case 0:
+ key->type = NCR_KEY_TYPE_SECRET;
+ break;
+ case 1:
+ key->type = NCR_KEY_TYPE_PUBLIC;
+ break;
+ case 2:
+ key->type = NCR_KEY_TYPE_PRIVATE;
+ break;
+ default:
+ err();
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+
+/* Unpack, or better decode the DER data
+ */
+static int key_from_packed_data(struct nlattr *tb[], struct key_item_st *key,
+ const void *data, size_t data_size)
+{
+ ltc_asn1_list list[6];
+ int ret, i, pkey_size, err;
+ unsigned long version, type;
+ uint8_t * pkey = NULL;
+ oid_st oid;
+
+ if (data_size > DER_KEY_MAX_SIZE) {
+ err();
+ return -EINVAL;
+ }
+
+ pkey_size = KEY_DATA_MAX_SIZE;
+ pkey = kmalloc(pkey_size, GFP_KERNEL);
+ if (pkey == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ i = 0;
+
+ list[i].type = LTC_ASN1_SHORT_INTEGER;
+ list[i].size = 1;
+ list[i++].data = &version;
+
+ list[i].type = LTC_ASN1_OBJECT_IDENTIFIER;
+ list[i].size = sizeof(oid.OID)/sizeof(oid.OID[0]);
+ list[i++].data = oid.OID;
+
+ list[i].type = LTC_ASN1_SHORT_INTEGER;
+ list[i].size = 1;
+ list[i++].data = &type;
+
+ list[i].type = LTC_ASN1_OCTET_STRING;
+ list[i].size = pkey_size;
+ list[i++].data = pkey;
+
+ err = der_decode_sequence(data, data_size, list, i);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ if (version != KEY_WRAP_VERSION) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ oid.OIDlen = list[1].size;
+ pkey_size = list[3].size;
+
+ ret = packed_type_to_key_type(type, key);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ key->algorithm = _ncr_oid_to_properties(&oid);
+ if (key->algorithm == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = ncr_key_update_flags(key, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret != 0) {
+ err();
+ return ret;
+ }
+
+
+#ifndef KEY_WRAP_IS_PRIVILEGED
+ /* Do not allow key unwrapping to result to exportable keys
+ */
+ if (current_euid() != 0)
+ key->flags &= (~NCR_KEY_FLAG_EXPORTABLE);
+#endif
+
+ if (key->type == NCR_KEY_TYPE_SECRET) {
+ if (data_size > NCR_CIPHER_MAX_KEY_LEN) {
+ err();
+ return -EINVAL;
+ }
+ key->key.secret.size = pkey_size;
+ memcpy(key->key.secret.data, pkey, pkey_size);
+ } else if (key->type == NCR_KEY_TYPE_PUBLIC
+ || key->type == NCR_KEY_TYPE_PRIVATE) {
+
+ ret = ncr_pk_unpack( key, pkey, pkey_size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ } else {
+ err();
+ return -EINVAL;
+ }
+
+ ret = 0;
+
+fail:
+ kfree(pkey);
+
+ return ret;
+}
diff --git a/crypto/userspace/ncr-key.c b/crypto/userspace/ncr-key.c
new file mode 100644
index 00000000000..e6f7f025848
--- /dev/null
+++ b/crypto/userspace/ncr-key.c
@@ -0,0 +1,832 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/audit.h>
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/ncr.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include <net/netlink.h>
+#include "ncr-int.h"
+#include "utils.h"
+
+static int key_list_deinit_fn(int id, void *item, void *unused)
+{
+ (void)unused;
+ _ncr_key_item_put(item);
+ return 0;
+}
+
+void ncr_key_list_deinit(struct ncr_lists *lst)
+{
+ /* The mutex is not necessary, but doesn't hurt and makes it easier to
+ verify locking correctness. */
+ mutex_lock(&lst->key_idr_mutex);
+ idr_for_each(&lst->key_idr, key_list_deinit_fn, NULL);
+ idr_remove_all(&lst->key_idr);
+ idr_destroy(&lst->key_idr);
+ mutex_unlock(&lst->key_idr_mutex);
+}
+
+/* returns the data item corresponding to desc */
+int ncr_key_item_get_read(struct key_item_st**st, struct ncr_lists *lst,
+ ncr_key_t desc)
+{
+struct key_item_st* item;
+int ret;
+
+ *st = NULL;
+
+ mutex_lock(&lst->key_idr_mutex);
+ item = idr_find(&lst->key_idr, desc);
+ if (item == NULL) {
+ err();
+ ret = -EINVAL;
+ goto exit;
+ }
+ atomic_inc(&item->refcnt);
+
+ if (atomic_read(&item->writer) != 0) {
+ /* writer in place busy */
+ atomic_dec(&item->refcnt);
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ *st = item;
+ ret = 0;
+
+exit:
+ mutex_unlock(&lst->key_idr_mutex);
+ return ret;
+}
+
+/* as above but will never return anything that
+ * is in use.
+ */
+int ncr_key_item_get_write( struct key_item_st** st,
+ struct ncr_lists *lst, ncr_key_t desc)
+{
+struct key_item_st* item;
+int ret;
+
+ *st = NULL;
+
+ mutex_lock(&lst->key_idr_mutex);
+ item = idr_find(&lst->key_idr, desc);
+ if (item == NULL) {
+ err();
+ ret = -EINVAL;
+ goto exit;
+ }
+ /* do not return items that are in use already */
+
+ if (atomic_add_unless(&item->writer, 1, 1)==0) {
+ /* another writer so busy */
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ if (atomic_add_unless(&item->refcnt, 1, 2)==0) {
+ /* some reader is active so busy */
+ atomic_dec(&item->writer);
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ *st = item;
+ ret = 0;
+
+exit:
+ mutex_unlock(&lst->key_idr_mutex);
+ return ret;
+}
+
+void _ncr_key_item_put( struct key_item_st* item)
+{
+ if (atomic_read(&item->writer) > 0)
+ atomic_dec(&item->writer);
+ if (atomic_dec_and_test(&item->refcnt)) {
+ ncr_limits_remove(item->uid, item->pid, LIMIT_TYPE_KEY);
+ ncr_key_clear(item);
+ kfree(item);
+ }
+}
+
+static void _ncr_key_remove(struct ncr_lists *lst, ncr_key_t desc)
+{
+ struct key_item_st * item;
+
+ mutex_lock(&lst->key_idr_mutex);
+ item = idr_find(&lst->key_idr, desc);
+ if (item != NULL)
+ idr_remove(&lst->key_idr, desc); /* Steal the reference */
+ mutex_unlock(&lst->key_idr_mutex);
+
+ if (item != NULL)
+ _ncr_key_item_put(item);
+}
+
+int ncr_key_init(struct ncr_lists *lst)
+{
+ ncr_key_t desc;
+ struct key_item_st* key;
+ int ret;
+
+ ret = ncr_limits_add_and_check(current_euid(), task_pid_nr(current), LIMIT_TYPE_KEY);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ key = kmalloc(sizeof(*key), GFP_KERNEL);
+ if (key == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto err_limits;
+ }
+
+ memset(key, 0, sizeof(*key));
+
+ atomic_set(&key->refcnt, 1);
+ atomic_set(&key->writer, 0);
+ key->uid = current_euid();
+ key->pid = task_pid_nr(current);
+ key->context_id = lst->id;
+
+ mutex_lock(&lst->key_idr_mutex);
+ /* idr_pre_get() should preallocate enough, and, due to key_idr_mutex,
+ nobody else can use the preallocated data. Therefore the loop
+ recommended in idr_get_new() documentation is not necessary. */
+ if (idr_pre_get(&lst->key_idr, GFP_KERNEL) == 0 ||
+ idr_get_new(&lst->key_idr, key, &key->desc) != 0) {
+ mutex_unlock(&lst->key_idr_mutex);
+ _ncr_key_item_put(key);
+ return -ENOMEM;
+ }
+ desc = key->desc;
+ mutex_unlock(&lst->key_idr_mutex);
+
+ return desc;
+
+err_limits:
+ ncr_limits_remove(current_euid(), task_pid_nr(current), LIMIT_TYPE_KEY);
+ return ret;
+}
+
+int ncr_key_deinit(struct ncr_lists *lst, ncr_key_t desc)
+{
+ _ncr_key_remove(lst, desc);
+ return 0;
+}
+
+int ncr_key_export(struct ncr_lists *lst, const struct ncr_key_export *data,
+ struct nlattr *tb[])
+{
+struct key_item_st* item = NULL;
+void* tmp = NULL;
+uint32_t tmp_size;
+int ret;
+
+ if (data->buffer_size < 0) {
+ err();
+ return -EINVAL;
+ }
+
+ ret = ncr_key_item_get_read(&item, lst, data->key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ if (!(item->flags & NCR_KEY_FLAG_EXPORTABLE)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ switch (item->type) {
+ case NCR_KEY_TYPE_SECRET:
+ if (item->key.secret.size > data->buffer_size) {
+ err();
+ ret = -ERANGE;
+ goto fail;
+ }
+
+ /* found */
+ if (item->key.secret.size > 0) {
+ ret = copy_to_user(data->buffer, item->key.secret.data, item->key.secret.size);
+ if (unlikely(ret)) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+ }
+
+ ret = item->key.secret.size;
+ break;
+ case NCR_KEY_TYPE_PUBLIC:
+ case NCR_KEY_TYPE_PRIVATE:
+ tmp_size = data->buffer_size;
+
+ tmp = kmalloc(tmp_size, GFP_KERNEL);
+ if (tmp == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ ret = ncr_pk_pack(item, tmp, &tmp_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = copy_to_user(data->buffer, tmp, tmp_size);
+ if (unlikely(ret)) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ ret = tmp_size;
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_EXPORT, lst->id, -1, NULL,
+ ncr_algorithm_name(item->algorithm), item->desc,
+ item->key_id, item->key_id_size, -1, NULL, 0);
+
+ kfree(tmp);
+ _ncr_key_item_put(item);
+ return ret;
+
+}
+
+int ncr_key_update_flags(struct key_item_st* item, const struct nlattr *nla)
+{
+ uint32_t flags;
+
+ if (nla == NULL)
+ return 0;
+ flags = nla_get_u32(nla);
+ if (!capable(CAP_SYS_ADMIN)
+ && (flags & (NCR_KEY_FLAG_WRAPPING | NCR_KEY_FLAG_UNWRAPPING)) != 0)
+ return -EPERM;
+ item->flags = flags;
+ return 0;
+}
+
+int ncr_key_import(struct ncr_lists *lst, const struct ncr_key_import *data,
+ struct nlattr *tb[])
+{
+const struct nlattr *nla;
+struct key_item_st* item = NULL;
+int ret;
+void* tmp = NULL;
+size_t tmp_size;
+
+ ret = ncr_key_item_get_write( &item, lst, data->key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ ncr_key_clear(item);
+
+ tmp = kmalloc(data->data_size, GFP_KERNEL);
+ if (tmp == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (unlikely(copy_from_user(tmp, data->data, data->data_size))) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+ tmp_size = data->data_size;
+
+ nla = tb[NCR_ATTR_KEY_TYPE];
+ if (tb == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ item->type = nla_get_u32(nla);
+
+ item->algorithm = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]);
+ if (item->algorithm == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = ncr_key_update_flags(item, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ nla = tb[NCR_ATTR_KEY_ID];
+ if (nla != NULL) {
+ if (nla_len(nla) > MAX_KEY_ID_SIZE) {
+ err();
+ ret = -EOVERFLOW;
+ goto fail;
+ }
+
+ item->key_id_size = nla_len(nla);
+ memcpy(item->key_id, nla_data(nla), item->key_id_size);
+ }
+
+ switch(item->type) {
+ case NCR_KEY_TYPE_SECRET:
+ if (tmp_size > NCR_CIPHER_MAX_KEY_LEN) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ memcpy(item->key.secret.data, tmp, tmp_size);
+ item->key.secret.size = tmp_size;
+ break;
+ case NCR_KEY_TYPE_PRIVATE:
+ case NCR_KEY_TYPE_PUBLIC:
+ ret = ncr_pk_unpack( item, tmp, tmp_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ break;
+
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_IMPORT, lst->id, -1, NULL,
+ ncr_algorithm_name(item->algorithm), item->desc,
+ item->key_id, item->key_id_size, -1, NULL, 0);
+
+ _ncr_key_item_put(item);
+ kfree(tmp);
+
+ return ret;
+}
+
+void ncr_key_clear(struct key_item_st* item)
+{
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_ZEROIZE, item->context_id, -1,
+ NULL, ncr_algorithm_name(item->algorithm),
+ item->desc, item->key_id, item->key_id_size, -1,
+ NULL, 0);
+ if (item->type == NCR_KEY_TYPE_PRIVATE ||
+ item->type == NCR_KEY_TYPE_PUBLIC)
+ ncr_pk_audit_values(item);
+
+ /* clears any previously allocated parameters */
+ if (item->type == NCR_KEY_TYPE_PRIVATE ||
+ item->type == NCR_KEY_TYPE_PUBLIC) {
+
+ ncr_pk_clear(item);
+ }
+ memset(&item->key, 0, sizeof(item->key));
+ memset(item->key_id, 0, sizeof(item->key_id));
+ item->key_id_size = 0;
+ item->flags = 0;
+
+ return;
+}
+
+/* Generate a secret key
+ */
+int ncr_key_generate(struct ncr_lists *lst, const struct ncr_key_generate *gen,
+ struct nlattr *tb[])
+{
+const struct nlattr *nla;
+struct key_item_st* item = NULL;
+const struct algo_properties_st *algo = NULL;
+int ret;
+size_t size;
+
+ ret = ncr_key_item_get_write(&item, lst, gen->key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ ncr_key_clear(item);
+
+ /* we generate only secret keys */
+ ret = ncr_key_update_flags(item, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ algo = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]);
+ if (algo == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ item->type = algo->key_type;
+ if (item->type == NCR_KEY_TYPE_SECRET) {
+ u32 key_bits;
+
+ item->algorithm = algo;
+
+ nla = tb[NCR_ATTR_SECRET_KEY_BITS];
+ if (nla == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ key_bits = nla_get_u32(nla);
+ size = key_bits / 8;
+ if (key_bits % 8 != 0 || size > NCR_CIPHER_MAX_KEY_LEN) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ get_random_bytes(item->key.secret.data, size);
+ item->key.secret.size = size;
+
+ /* generate random key id */
+ item->key_id_size = 5;
+ get_random_bytes(item->key_id, item->key_id_size);
+ } else {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_GEN, lst->id, -1, NULL,
+ ncr_algorithm_name(algo), item->desc, item->key_id,
+ item->key_id_size, -1, NULL, 0);
+ if (item->type == NCR_KEY_TYPE_PUBLIC
+ || item->type == NCR_KEY_TYPE_PRIVATE)
+ ncr_pk_audit_values(item);
+
+ if (ret < 0) item->type = NCR_KEY_TYPE_INVALID;
+ _ncr_key_item_put(item);
+ return ret;
+}
+
+/* Those values are derived from "ECRYPT II Yearly Report on Algorithms and
+ * Keysizes (2009-2010)". It maps the strength of public key algorithms to
+ * symmetric ones. Should be kept up to date.
+ */
+static const struct {
+ unsigned int bits; /* sec level */
+ unsigned int rsa_bits;
+ unsigned int dlog_bits;
+} ecrypt_vals[] = {
+ {64, 816, 816},
+ {80, 1248, 1248},
+ {112, 2432, 2432},
+ {128, 3248, 3248},
+ {160, 5312, 5312},
+ {192, 7936, 7936},
+ {256, 15424, 15424},
+ {0,0,0}
+};
+
+static unsigned int rsa_to_bits(unsigned int rsa_bits)
+{
+int i = 1;
+
+ if (rsa_bits <= ecrypt_vals[0].rsa_bits)
+ return ecrypt_vals[0].rsa_bits;
+
+ do {
+ if (rsa_bits <= ecrypt_vals[i].rsa_bits &&
+ rsa_bits > ecrypt_vals[i-1].rsa_bits) {
+
+ return ecrypt_vals[i].bits;
+ }
+ } while(ecrypt_vals[++i].bits != 0);
+
+ /* return the highest found so far */
+ return ecrypt_vals[i-1].bits;
+}
+
+static unsigned int dlog_to_bits(unsigned int dlog_bits)
+{
+int i = 1;
+
+ if (dlog_bits <= ecrypt_vals[0].dlog_bits)
+ return ecrypt_vals[0].dlog_bits;
+
+ do {
+ if (dlog_bits <= ecrypt_vals[i].dlog_bits &&
+ dlog_bits > ecrypt_vals[i-1].dlog_bits) {
+
+ return ecrypt_vals[i].bits;
+ }
+ } while(ecrypt_vals[++i].bits != 0);
+
+ /* return the highest found so far */
+ return ecrypt_vals[i-1].bits;
+}
+
+/* returns the security level of the key in bits. Private/Public keys
+ * are mapped to symmetric key bits using the ECRYPT II 2010 recommendation.
+ */
+int _ncr_key_get_sec_level(struct key_item_st* item)
+{
+int bits;
+
+ /* FIXME: should we move everything here into algorithm properties?
+ */
+ if (item->type == NCR_KEY_TYPE_SECRET) {
+ if (item->algorithm->algo == NCR_ALG_3DES_CBC || item->algorithm->algo == NCR_ALG_3DES_ECB)
+ return 112;
+
+ return item->key.secret.size*8;
+ } else if (item->type == NCR_KEY_TYPE_PRIVATE) {
+ switch(item->algorithm->algo) {
+ case NCR_ALG_RSA:
+ bits = ncr_pk_get_rsa_size(&item->key.pk.rsa);
+ if (bits < 0) {
+ err();
+ return bits;
+ }
+
+ return rsa_to_bits(bits);
+ case NCR_ALG_DSA:
+ bits = ncr_pk_get_dsa_size(&item->key.pk.dsa);
+ if (bits < 0) {
+ err();
+ return bits;
+ }
+
+ return dlog_to_bits(bits);
+ case NCR_ALG_DH:
+ bits = ncr_pk_get_dh_size(&item->key.pk.dh);
+ if (bits < 0) {
+ err();
+ return bits;
+ }
+
+ return dlog_to_bits(bits);
+ default:
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+}
+
+int ncr_key_get_info(struct ncr_lists *lst, struct ncr_out *out,
+ const struct ncr_key_get_info *info, struct nlattr *tb[])
+{
+const struct nlattr *nla;
+const u16 *attr, *attr_end;
+struct key_item_st* item = NULL;
+int ret;
+
+ ret = ncr_key_item_get_read(&item, lst, info->key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ if (item->type == NCR_KEY_TYPE_INVALID) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ nla = tb[NCR_ATTR_WANTED_ATTRS];
+ if (nla == NULL || nla_len(nla) % sizeof(u16) != 0) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ attr = nla_data(nla);
+ attr_end = attr + nla_len(nla) / sizeof(u16);
+ while (attr < attr_end) {
+ switch (*attr) {
+ case NCR_ATTR_KEY_FLAGS:
+ ret = ncr_out_put_u32(out, *attr, item->flags);
+ break;
+ case NCR_ATTR_KEY_TYPE:
+ ret = ncr_out_put_u32(out, *attr, item->type);
+ break;
+ case NCR_ATTR_ALGORITHM:
+ ret = ncr_out_put_string(out, *attr,
+ item->algorithm->kstr);
+ break;
+ default:
+ break; /* Silently ignore */
+ }
+ if (ret != 0) {
+ err();
+ goto fail;
+ }
+ attr++;
+ }
+
+ ret = ncr_out_finish(out);
+ if (ret != 0) {
+ err();
+ goto fail;
+ }
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_GET_INFO, lst->id, -1, NULL,
+ ncr_algorithm_name(item->algorithm), item->desc,
+ item->key_id, item->key_id_size, -1, NULL, 0);
+
+ _ncr_key_item_put( item);
+
+ return ret;
+}
+
+int ncr_key_generate_pair(struct ncr_lists *lst,
+ const struct ncr_key_generate_pair *gen,
+ struct nlattr *tb[])
+{
+struct key_item_st* private = NULL;
+struct key_item_st* public = NULL;
+int ret;
+
+ ret = ncr_key_item_get_write(&private, lst, gen->private_key);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = ncr_key_item_get_write(&public, lst, gen->public_key);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ncr_key_clear(public);
+ ncr_key_clear(private);
+
+ /* we generate only secret keys */
+ private->algorithm = public->algorithm
+ = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]);
+ if (private->algorithm == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ public->type = public->algorithm->key_type;
+ private->type = NCR_KEY_TYPE_PRIVATE;
+ ret = ncr_key_update_flags(private, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ ret = ncr_key_update_flags(public, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ public->flags |= (NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE);
+
+ if (public->type == NCR_KEY_TYPE_PUBLIC) {
+ ret = ncr_pk_generate(public->algorithm, tb, private, public);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ } else {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_GEN, lst->id, -1, NULL,
+ ncr_algorithm_name(private != NULL
+ ? private->algorithm : NULL),
+ private != NULL ? private->desc : -1,
+ private != NULL ? private->key_id : NULL,
+ private != NULL ? private->key_id_size : 0,
+ public != NULL ? public->desc : -1,
+ public != NULL ? public->key_id : NULL,
+ public != NULL ? public->key_id_size : 0);
+ if (public != NULL && ret >= 0)
+ ncr_pk_audit_values(public);
+
+ if (public) {
+ if (ret < 0) public->type = NCR_KEY_TYPE_INVALID;
+ _ncr_key_item_put(public);
+ }
+ if (private) {
+ if (ret < 0) private->type = NCR_KEY_TYPE_INVALID;
+ _ncr_key_item_put(private);
+ }
+ return ret;
+}
+
+int ncr_key_derive(struct ncr_lists *lst, const struct ncr_key_derive *data,
+ struct nlattr *tb[])
+{
+int ret;
+struct key_item_st* key = NULL;
+struct key_item_st* newkey = NULL;
+
+ ret = ncr_key_item_get_read(&key, lst, data->input_key);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ /* wrapping keys cannot be used for anything except wrapping.
+ */
+ if (key->flags & NCR_KEY_FLAG_WRAPPING || key->flags & NCR_KEY_FLAG_UNWRAPPING) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = ncr_key_item_get_write(&newkey, lst, data->new_key);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ncr_key_clear(newkey);
+
+ ret = ncr_key_update_flags(newkey, tb[NCR_ATTR_KEY_FLAGS]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ switch (key->type) {
+ case NCR_KEY_TYPE_PUBLIC:
+ case NCR_KEY_TYPE_PRIVATE:
+ ret = ncr_pk_derive(newkey, key, tb);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_DERIVE, lst->id, -1, NULL,
+ ncr_algorithm_name(key->algorithm), key->desc,
+ key->key_id, key->key_id_size, data->input_key,
+ newkey != NULL ? newkey->key_id : NULL,
+ newkey != NULL ? newkey->key_id_size : 0);
+
+ _ncr_key_item_put(key);
+ if (newkey)
+ _ncr_key_item_put(newkey);
+ return ret;
+
+}
+
diff --git a/crypto/userspace/ncr-limits.c b/crypto/userspace/ncr-limits.c
new file mode 100644
index 00000000000..345cca74603
--- /dev/null
+++ b/crypto/userspace/ncr-limits.c
@@ -0,0 +1,247 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/hash.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/ncr.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/random.h>
+#include <asm/atomic.h>
+#include <linux/version.h>
+#include <linux/file.h>
+#include <linux/cred.h>
+#include "ncr-int.h"
+
+/* arbitrary now */
+static unsigned int max_per_user[] = {
+ [LIMIT_TYPE_KEY] = 128,
+};
+
+static unsigned int max_per_process[] = {
+ [LIMIT_TYPE_KEY] = 64,
+};
+
+struct limit_user_item_st {
+ struct hlist_node hlist;
+ uid_t uid;
+ atomic_t cnt[NUM_LIMIT_TYPES];
+};
+
+struct limit_process_item_st {
+ struct hlist_node hlist;
+ pid_t pid;
+ atomic_t cnt[NUM_LIMIT_TYPES];
+};
+
+static struct mutex user_limit_mutex;
+#define USER_LIMIT_HASH_BITS 7
+#define USER_LIMIT_TABLE_SIZE (1 << USER_LIMIT_HASH_BITS)
+static struct hlist_head user_limit_table[USER_LIMIT_TABLE_SIZE];
+
+static struct hlist_head *user_limit_hash(uid_t uid)
+{
+ return &user_limit_table[hash_long(uid, USER_LIMIT_HASH_BITS)];
+}
+
+static struct mutex process_limit_mutex;
+#define PROCESS_LIMIT_HASH_BITS 9
+#define PROCESS_LIMIT_TABLE_SIZE (1 << PROCESS_LIMIT_HASH_BITS)
+static struct hlist_head process_limit_table[PROCESS_LIMIT_TABLE_SIZE];
+
+static struct hlist_head *process_limit_hash(pid_t pid)
+{
+ return &process_limit_table[hash_long(pid, PROCESS_LIMIT_HASH_BITS)];
+}
+
+void ncr_limits_init(void)
+{
+ size_t i;
+
+ mutex_init(&user_limit_mutex);
+ for (i = 0; i < USER_LIMIT_TABLE_SIZE; i++)
+ INIT_HLIST_HEAD(&user_limit_table[i]);
+
+ mutex_init(&process_limit_mutex);
+ for (i = 0; i < PROCESS_LIMIT_TABLE_SIZE; i++)
+ INIT_HLIST_HEAD(&process_limit_table[i]);
+}
+
+void ncr_limits_deinit(void)
+{
+struct limit_process_item_st* pitem;
+struct limit_user_item_st* uitem;
+struct hlist_node *pos, *tmp;
+size_t i;
+
+ mutex_lock(&user_limit_mutex);
+ for (i = 0; i < USER_LIMIT_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(uitem, pos, tmp, &user_limit_table[i],
+ hlist) {
+ hlist_del(&uitem->hlist);
+ kfree(uitem);
+ }
+ }
+ mutex_unlock(&user_limit_mutex);
+
+ mutex_lock(&process_limit_mutex);
+ for (i = 0; i < PROCESS_LIMIT_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(pitem, pos, tmp,
+ &process_limit_table[i], hlist) {
+ hlist_del(&pitem->hlist);
+ kfree(pitem);
+ }
+ }
+ mutex_unlock(&process_limit_mutex);
+
+}
+
+int ncr_limits_add_and_check(uid_t uid, pid_t pid, limits_type_t type)
+{
+struct limit_process_item_st* pitem;
+struct limit_user_item_st* uitem;
+struct hlist_head *user_head, *process_head;
+struct hlist_node *pos;
+int add = 1;
+int ret;
+ BUG_ON(type >= NUM_LIMIT_TYPES);
+
+ user_head = user_limit_hash(uid);
+ mutex_lock(&user_limit_mutex);
+ hlist_for_each_entry(uitem, pos, user_head, hlist) {
+ if (uitem->uid == uid) {
+ add = 0;
+
+ if (atomic_add_unless(&uitem->cnt[type], 1, max_per_user[type])==0) {
+ err();
+ mutex_unlock(&user_limit_mutex);
+ return -EPERM;
+ }
+ break;
+ }
+ }
+
+ if (add) {
+ size_t i;
+
+ uitem = kmalloc( sizeof(*uitem), GFP_KERNEL);
+ if (uitem == NULL) {
+ err();
+ mutex_unlock(&user_limit_mutex);
+ return -ENOMEM;
+ }
+ uitem->uid = uid;
+ for (i = 0; i < NUM_LIMIT_TYPES; i++)
+ atomic_set(&uitem->cnt[i], 0);
+ atomic_set(&uitem->cnt[type], 1);
+
+ hlist_add_head(&uitem->hlist, user_head);
+ }
+ mutex_unlock(&user_limit_mutex);
+
+ add = 1;
+ /* check process limits */
+ process_head = process_limit_hash(uid);
+ mutex_lock(&process_limit_mutex);
+ hlist_for_each_entry(pitem, pos, process_head, hlist) {
+ if (pitem->pid == pid) {
+ add = 0;
+ if (atomic_add_unless(&pitem->cnt[type], 1, max_per_process[type])==0) {
+ err();
+ mutex_unlock(&process_limit_mutex);
+
+ ret = -EPERM;
+ goto restore_user;
+ }
+ break;
+ }
+ }
+
+
+ if (add) {
+ size_t i;
+
+ pitem = kmalloc(sizeof(*pitem), GFP_KERNEL);
+ if (pitem == NULL) {
+ err();
+ mutex_unlock(&process_limit_mutex);
+ ret = -ENOMEM;
+ goto restore_user;
+ }
+ pitem->pid = pid;
+ for (i = 0; i < NUM_LIMIT_TYPES; i++)
+ atomic_set(&pitem->cnt[i], 0);
+ atomic_set(&pitem->cnt[type], 1);
+
+ hlist_add_head(&pitem->hlist, process_head);
+ }
+ mutex_unlock(&process_limit_mutex);
+
+ return 0;
+
+restore_user:
+ mutex_lock(&user_limit_mutex);
+ hlist_for_each_entry(uitem, pos, user_head, hlist) {
+ if (uitem->uid == uid) {
+ atomic_dec(&uitem->cnt[type]);
+ break;
+ }
+ }
+ mutex_unlock(&user_limit_mutex);
+ return ret;
+}
+
+void ncr_limits_remove(uid_t uid, pid_t pid, limits_type_t type)
+{
+struct limit_process_item_st* pitem;
+struct limit_user_item_st* uitem;
+struct hlist_head *hhead;
+struct hlist_node *pos;
+
+ BUG_ON(type >= NUM_LIMIT_TYPES);
+ hhead = user_limit_hash(uid);
+ mutex_lock(&user_limit_mutex);
+ hlist_for_each_entry(uitem, pos, hhead, hlist) {
+ if (uitem->uid == uid) {
+ atomic_dec(&uitem->cnt[type]);
+ break;
+ }
+ }
+ mutex_unlock(&user_limit_mutex);
+
+ /* check process limits */
+ hhead = process_limit_hash(uid);
+ mutex_lock(&process_limit_mutex);
+ hlist_for_each_entry(pitem, pos, hhead, hlist) {
+ if (pitem->pid == pid) {
+ atomic_dec(&pitem->cnt[type]);
+ break;
+ }
+ }
+ mutex_unlock(&process_limit_mutex);
+
+ return;
+}
diff --git a/crypto/userspace/ncr-pk.c b/crypto/userspace/ncr-pk.c
new file mode 100644
index 00000000000..c858c2aeb18
--- /dev/null
+++ b/crypto/userspace/ncr-pk.c
@@ -0,0 +1,749 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/audit.h>
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/ncr.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include <net/netlink.h>
+#include "ncr-int.h"
+#include <tomcrypt.h>
+
+int _ncr_tomerr(int err)
+{
+ switch (err) {
+ case CRYPT_BUFFER_OVERFLOW:
+ return -ERANGE;
+ case CRYPT_MEM:
+ return -ENOMEM;
+ default:
+ return -EINVAL;
+ }
+}
+
+void ncr_pk_clear(struct key_item_st* key)
+{
+ if (key->algorithm == NULL)
+ return;
+ switch(key->algorithm->algo) {
+ case NCR_ALG_RSA:
+ rsa_free(&key->key.pk.rsa);
+ break;
+ case NCR_ALG_DSA:
+ dsa_free(&key->key.pk.dsa);
+ break;
+ case NCR_ALG_DH:
+ dh_free(&key->key.pk.dh);
+ break;
+ default:
+ return;
+ }
+}
+
+static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_item_st * public)
+{
+ uint8_t * tmp;
+ unsigned long max_size;
+ int ret, cret;
+ unsigned long key_id_size;
+
+ max_size = KEY_DATA_MAX_SIZE;
+ tmp = kmalloc(max_size, GFP_KERNEL);
+ if (tmp == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ switch(private->algorithm->algo) {
+ case NCR_ALG_RSA:
+ cret = rsa_export(tmp, &max_size, PK_PUBLIC, &private->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+
+ cret = rsa_import(tmp, max_size, &public->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+ break;
+ case NCR_ALG_DSA:
+ cret = dsa_export(tmp, &max_size, PK_PUBLIC, &private->key.pk.dsa);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+
+ cret = dsa_import(tmp, max_size, &public->key.pk.dsa);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+ break;
+ case NCR_ALG_DH:
+ ret = dh_generate_public(&public->key.pk.dh, &private->key.pk.dh);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ key_id_size = MAX_KEY_ID_SIZE;
+ cret = hash_memory(_ncr_algo_to_properties(NCR_ALG_SHA1), tmp, max_size,
+ private->key_id, &key_id_size);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+ private->key_id_size = public->key_id_size = key_id_size;
+ memcpy(public->key_id, private->key_id, key_id_size);
+
+ ret = 0;
+fail:
+ kfree(tmp);
+
+ return ret;
+}
+
+int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * packed_size)
+{
+ unsigned long max_size = *packed_size;
+ int cret, ret;
+
+ if (packed == NULL || packed_size == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ switch(key->algorithm->algo) {
+ case NCR_ALG_RSA:
+ cret = rsa_export(packed, &max_size, key->key.pk.rsa.type, (void*)&key->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ *packed_size = max_size;
+ err();
+ return _ncr_tomerr(cret);
+ }
+ break;
+ case NCR_ALG_DSA:
+ cret = dsa_export(packed, &max_size, key->key.pk.dsa.type, (void*)&key->key.pk.dsa);
+ if (cret != CRYPT_OK) {
+ *packed_size = max_size;
+ err();
+ return _ncr_tomerr(cret);
+ }
+ break;
+ case NCR_ALG_DH:
+ ret = dh_export(packed, &max_size, key->key.pk.dh.type, (void*)&key->key.pk.dh);
+ if (ret < 0) {
+ *packed_size = max_size;
+ err();
+ return ret;
+ }
+ break;
+ default:
+ err();
+ return -EINVAL;
+ }
+
+ *packed_size = max_size;
+
+ return 0;
+}
+
+int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_size)
+{
+ int cret, ret;
+
+ if (key == NULL || packed == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ switch(key->algorithm->algo) {
+ case NCR_ALG_RSA:
+ cret = rsa_import(packed, packed_size, (void*)&key->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(cret);
+ }
+ break;
+ case NCR_ALG_DSA:
+ cret = dsa_import(packed, packed_size, (void*)&key->key.pk.dsa);
+ if (cret != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(cret);
+ }
+ break;
+ case NCR_ALG_DH:
+ ret = dh_import(packed, packed_size, (void*)&key->key.pk.dh);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ break;
+ default:
+ err();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int binary_to_ulong(unsigned long *dest, const struct nlattr *nla)
+{
+ unsigned long value;
+ const uint8_t *start, *end, *p;
+
+ value = 0;
+ start = nla_data(nla);
+ end = start + nla_len(nla);
+ for (p = start; p < end; p++) {
+ if (value > (ULONG_MAX - *p) / 256)
+ return -EOVERFLOW;
+ value = value * 256 + *p;
+ }
+ *dest = value;
+ return 0;
+}
+
+int ncr_pk_generate(const struct algo_properties_st *algo, struct nlattr *tb[],
+ struct key_item_st* private, struct key_item_st* public)
+{
+ const struct nlattr *nla;
+ unsigned long e;
+ int cret, ret;
+
+ private->algorithm = public->algorithm = algo;
+
+ ret = 0;
+ switch(algo->algo) {
+ case NCR_ALG_RSA:
+ nla = tb[NCR_ATTR_RSA_E];
+ if (nla != NULL) {
+ ret = binary_to_ulong(&e, nla);
+ if (ret != 0)
+ break;
+ } else
+ e = 65537;
+
+ nla = tb[NCR_ATTR_RSA_MODULUS_BITS];
+ if (nla == NULL) {
+ ret = -EINVAL;
+ break;
+ }
+ cret = rsa_make_key(nla_get_u32(nla) / 8, e, &private->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(cret);
+ }
+ break;
+ case NCR_ALG_DSA: {
+ u32 q_bits, p_bits;
+
+ nla = tb[NCR_ATTR_DSA_Q_BITS];
+ if (nla != NULL)
+ q_bits = nla_get_u32(nla);
+ else
+ q_bits = 160;
+ nla = tb[NCR_ATTR_DSA_P_BITS];
+ if (nla != NULL)
+ p_bits = nla_get_u32(nla);
+ else
+ p_bits = 1024;
+ cret = dsa_make_key(q_bits / 8, p_bits / 8,
+ &private->key.pk.dsa);
+ if (cret != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(cret);
+ }
+ break;
+ }
+ case NCR_ALG_DH: {
+ const struct nlattr *p, *g;
+
+ p = tb[NCR_ATTR_DH_PRIME];
+ g = tb[NCR_ATTR_DH_BASE];
+ if (p == NULL || g == NULL) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = dh_import_params(&private->key.pk.dh, nla_data(p),
+ nla_len(p), nla_data(g),
+ nla_len(g));
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = dh_generate_key(&private->key.pk.dh);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ break;
+ }
+ default:
+ err();
+ return -EINVAL;
+ }
+
+fail:
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ ret = ncr_pk_make_public_and_id(private, public);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_AUDIT
+static int
+set_crypto_value(struct audit_crypto_value *dst, char name, mp_int *src)
+{
+ int cret;
+
+ dst->name = name;
+ dst->value_size = mp_unsigned_bin_size(src);
+ dst->value = kmalloc(dst->value_size, GFP_KERNEL);
+ cret = mp_to_unsigned_bin(src, dst->value);
+ if (cret != CRYPT_OK) {
+ kfree(dst->value);
+ return _ncr_tomerr(cret);
+ }
+ return 0;
+}
+
+void ncr_pk_audit_values(struct key_item_st *key)
+{
+ struct audit_crypto_value v[4];
+ size_t i;
+
+ i = 0;
+ switch (key->algorithm->algo) {
+#define VALUE(NAME, MPI) \
+ do { \
+ if (set_crypto_value(v + i, (NAME), (MPI)) != 0) \
+ goto free_it; \
+ i++; \
+ } while (0)
+
+ case NCR_ALG_RSA:
+ VALUE('n', &key->key.pk.rsa.N);
+ VALUE('e', &key->key.pk.rsa.e);
+ break;
+
+ case NCR_ALG_DSA:
+ VALUE('p', &key->key.pk.dsa.p);
+ VALUE('q', &key->key.pk.dsa.q);
+ VALUE('g', &key->key.pk.dsa.g);
+ VALUE('y', &key->key.pk.dsa.y);
+ break;
+
+ case NCR_ALG_DH:
+ VALUE('y', &key->key.pk.dh.y);
+ break;
+
+ default:
+ return;
+#undef VALUE
+ }
+ audit_log_crypto_values(v, i);
+ return;
+
+free_it:
+ while (i != 0) {
+ i--;
+ kfree(v[i].value);
+ }
+}
+#endif
+
+
+/* Encryption/Decryption
+ */
+
+void ncr_pk_cipher_deinit(struct ncr_pk_ctx* ctx)
+{
+ if (ctx->init) {
+ ctx->init = 0;
+ ctx->key = NULL;
+ }
+}
+
+int ncr_pk_cipher_init(const struct algo_properties_st *algo,
+ struct ncr_pk_ctx* ctx, struct nlattr *tb[],
+ struct key_item_st *key,
+ const struct algo_properties_st *sign_hash)
+{
+ const struct nlattr *nla;
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ /* Allow using the same key for transparent and non-transparent
+ hashing. */
+ if (key->algorithm->algo != algo->algo) {
+ err();
+ return -EINVAL;
+ }
+
+ ctx->algorithm = algo;
+ ctx->key = key;
+ ctx->sign_hash = sign_hash;
+ ctx->salt_len = 0;
+
+ switch(algo->algo) {
+ case NCR_ALG_RSA:
+ nla = tb[NCR_ATTR_RSA_ENCODING_METHOD];
+ if (nla == NULL) {
+ err();
+ return -EINVAL;
+ }
+ switch (nla_get_u32(nla)) {
+ case RSA_PKCS1_V1_5:
+ ctx->type = LTC_LTC_PKCS_1_V1_5;
+ break;
+ case RSA_PKCS1_OAEP:
+ ctx->type = LTC_LTC_PKCS_1_OAEP;
+ nla = tb[NCR_ATTR_RSA_OAEP_HASH_ALGORITHM];
+ ctx->oaep_hash = _ncr_nla_to_properties(nla);
+ if (ctx->oaep_hash == NULL) {
+ err();
+ return -EINVAL;
+ }
+ break;
+ case RSA_PKCS1_PSS:
+ ctx->type = LTC_LTC_PKCS_1_PSS;
+ nla = tb[NCR_ATTR_RSA_PSS_SALT_LENGTH];
+ if (nla != NULL)
+ ctx->salt_len = nla_get_u32(nla);
+ break;
+ default:
+ err();
+ return -EINVAL;
+ }
+ break;
+ case NCR_ALG_DSA:
+ break;
+ default:
+ err();
+ return -EINVAL;
+ }
+
+ ctx->init = 1;
+
+ return 0;
+}
+
+int ncr_pk_cipher_encrypt(const struct ncr_pk_ctx* ctx,
+ const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size,
+ struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size)
+{
+int cret, ret;
+unsigned long osize = *osg_size;
+uint8_t* tmp;
+void * input, *output;
+
+ tmp = kmalloc(isg_size + *osg_size, GFP_KERNEL);
+ if (tmp == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ ret = sg_copy_to_buffer((struct scatterlist*)isg, isg_cnt, tmp, isg_size);
+ if (ret != isg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ input = tmp;
+ output = &tmp[isg_size];
+
+
+ switch(ctx->algorithm->algo) {
+ case NCR_ALG_RSA:
+ cret = rsa_encrypt_key_ex( input, isg_size, output, &osize,
+ NULL, 0, ctx->oaep_hash, ctx->type, &ctx->key->key.pk.rsa);
+
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+ *osg_size = osize;
+
+ break;
+ case NCR_ALG_DSA:
+ ret = -EINVAL;
+ goto fail;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = sg_copy_from_buffer(osg, osg_cnt, output, *osg_size);
+ if (ret != *osg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ kfree(tmp);
+ return ret;
+}
+
+int ncr_pk_cipher_decrypt(const struct ncr_pk_ctx* ctx,
+ const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size,
+ struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size)
+{
+int cret, ret;
+int stat;
+unsigned long osize = *osg_size;
+uint8_t* tmp;
+void * input, *output;
+
+ tmp = kmalloc(isg_size + *osg_size, GFP_KERNEL);
+ if (tmp == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ input = tmp;
+ output = &tmp[isg_size];
+
+ ret = sg_copy_to_buffer((struct scatterlist*)isg, isg_cnt, input, isg_size);
+ if (ret != isg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ switch(ctx->algorithm->algo) {
+ case NCR_ALG_RSA:
+ cret = rsa_decrypt_key_ex( input, isg_size, output, &osize,
+ NULL, 0, ctx->oaep_hash, ctx->type, &stat, &ctx->key->key.pk.rsa);
+
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+
+ if (stat==0) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ *osg_size = osize;
+ break;
+ case NCR_ALG_DSA:
+ ret = -EINVAL;
+ goto fail;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = sg_copy_from_buffer(osg, osg_cnt, output, *osg_size);
+ if (ret != *osg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ kfree(tmp);
+
+ return ret;
+}
+
+int ncr_pk_cipher_sign(const struct ncr_pk_ctx *ctx, const void *hash,
+ size_t hash_size, void *sig, size_t *sig_size)
+{
+ int cret;
+ unsigned long osize = *sig_size;
+
+ switch(ctx->algorithm->algo) {
+ case NCR_ALG_RSA:
+ if (ctx->sign_hash == NULL) {
+ err();
+ return -EINVAL;
+ }
+ cret = rsa_sign_hash_ex(hash, hash_size, sig, &osize,
+ ctx->type, ctx->sign_hash, ctx->salt_len, &ctx->key->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(cret);
+ }
+ *sig_size = osize;
+ break;
+ case NCR_ALG_DSA:
+ cret = dsa_sign_hash(hash, hash_size, sig, &osize,
+ &ctx->key->key.pk.dsa);
+
+ if (cret != CRYPT_OK) {
+ err();
+ return _ncr_tomerr(cret);
+ }
+ *sig_size = osize;
+ break;
+ default:
+ err();
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx, const void *sig,
+ size_t sig_size, const void *hash, size_t hash_size)
+{
+ int cret, ret, stat;
+
+ switch(ctx->algorithm->algo) {
+ case NCR_ALG_RSA:
+ if (ctx->sign_hash == NULL) {
+ err();
+ return -EINVAL;
+ }
+ cret = rsa_verify_hash_ex(sig, sig_size, hash,
+ hash_size, ctx->type,
+ ctx->sign_hash, ctx->salt_len,
+ &stat, &ctx->key->key.pk.rsa);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+
+ ret = (stat == 1);
+ break;
+ case NCR_ALG_DSA:
+ cret = dsa_verify_hash(sig, sig_size, hash, hash_size,
+ &stat, &ctx->key->key.pk.dsa);
+ if (cret != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+
+ ret = (stat == 1);
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+fail:
+ return ret;
+}
+
+int ncr_pk_derive(struct key_item_st* newkey, struct key_item_st* oldkey,
+ struct nlattr *tb[])
+{
+const struct nlattr *nla;
+int ret;
+
+ nla = tb[NCR_ATTR_DERIVATION_ALGORITHM];
+ if (nla == NULL) {
+ err();
+ return -EINVAL;
+ }
+ if (nla_strcmp(nla, NCR_DERIVE_DH) == 0) {
+ if (oldkey->type != NCR_KEY_TYPE_PRIVATE &&
+ oldkey->algorithm->algo != NCR_ALG_DH) {
+ err();
+ return -EINVAL;
+ }
+
+ nla = tb[NCR_ATTR_DH_PUBLIC];
+ if (nla == NULL) {
+ err();
+ return -EINVAL;
+ }
+ ret = dh_derive_gxy(newkey, &oldkey->key.pk.dh, nla_data(nla),
+ nla_len(nla));
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ } else {
+ err();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int ncr_pk_get_rsa_size( rsa_key* key)
+{
+int ret;
+ ret = mp_count_bits(&key->N);
+ if (ret <= 0) {
+ err();
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int ncr_pk_get_dsa_size( dsa_key* key)
+{
+int ret;
+ ret = mp_count_bits(&key->p);
+ if (ret <= 0) {
+ err();
+ return -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/crypto/userspace/ncr-pk.h b/crypto/userspace/ncr-pk.h
new file mode 100644
index 00000000000..1d4b8067d36
--- /dev/null
+++ b/crypto/userspace/ncr-pk.h
@@ -0,0 +1,64 @@
+#ifndef NCR_PK_H
+# define NCR_PK_H
+
+#include <tomcrypt.h>
+
+struct nlattr;
+
+struct ncr_pk_ctx {
+ const struct algo_properties_st *algorithm; /* algorithm */
+
+ const struct algo_properties_st *sign_hash; /* for verification */
+
+ const struct algo_properties_st *oaep_hash;
+ int salt_len; /* for RSA-PSS signatures */
+
+ int type; /* libtomcrypt type */
+ int init; /* non zero if initialized */
+
+ struct key_item_st * key;
+};
+
+/* PK */
+void ncr_pk_clear(struct key_item_st* key);
+int ncr_pk_generate(const struct algo_properties_st *algo, struct nlattr *tb[],
+ struct key_item_st* private, struct key_item_st* public);
+int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * packed_size);
+int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_size);
+#ifdef CONFIG_AUDIT
+void ncr_pk_audit_values(struct key_item_st *key);
+#else
+#define ncr_pk_audit_values(key) ((void)0)
+#endif
+
+/* encryption/decryption */
+int ncr_pk_cipher_init(const struct algo_properties_st *algo,
+ struct ncr_pk_ctx* ctx, struct nlattr *tb[],
+ struct key_item_st *key,
+ const struct algo_properties_st *sign_hash);
+void ncr_pk_cipher_deinit(struct ncr_pk_ctx* ctx);
+
+int ncr_pk_cipher_encrypt(const struct ncr_pk_ctx* ctx,
+ const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size,
+ struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size);
+
+int ncr_pk_cipher_decrypt(const struct ncr_pk_ctx* ctx,
+ const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size,
+ struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size);
+
+int ncr_pk_cipher_sign(const struct ncr_pk_ctx *ctx, const void *hash,
+ size_t hash_size, void *sig, size_t *sig_size);
+
+int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx, const void *sig,
+ size_t sig_size, const void *hash, size_t hash_size);
+
+int _ncr_tomerr(int err);
+
+int ncr_pk_derive(struct key_item_st* newkey, struct key_item_st* oldkey,
+ struct nlattr *tb[]);
+
+int ncr_pk_get_rsa_size( rsa_key* key);
+int ncr_pk_get_dsa_size( dsa_key* key);
+
+
+#endif
diff --git a/crypto/userspace/ncr-sessions.c b/crypto/userspace/ncr-sessions.c
new file mode 100644
index 00000000000..b344d087b47
--- /dev/null
+++ b/crypto/userspace/ncr-sessions.c
@@ -0,0 +1,1506 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ * Portions Copyright (c) 2010 Phil Sutter
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/audit.h>
+#include <linux/crypto.h>
+#include <linux/mutex.h>
+#include <linux/ncr.h>
+#include "ncr-int.h"
+#include <linux/mm_types.h>
+#include <linux/scatterlist.h>
+#include <net/netlink.h>
+
+struct session_item_st {
+ atomic_t refcnt;
+ /* Constant values throughout the life of this object follow. */
+ ncr_session_t desc;
+ const struct algo_properties_st *algorithm;
+ ncr_crypto_op_t op;
+ struct key_item_st *key;
+
+ /* Variable values, protected usually by mutex, follow. */
+ struct mutex mutex;
+
+ /* contexts for various options.
+ * simpler to have them like that than
+ * in a union.
+ */
+ struct cipher_data cipher;
+ struct ncr_pk_ctx pk;
+ struct hash_data hash;
+ /* This is a hack, ideally we'd have a hash algorithm that simply
+ outputs its input as a digest. We'd still need to distinguish
+ between the hash to identify in the signature and the hash to
+ actually use, though. */
+ void *transparent_hash;
+
+ struct scatterlist *sg;
+ struct page **pages;
+ unsigned array_size;
+ unsigned available_pages;
+};
+
+static void _ncr_sessions_item_put(struct session_item_st *item);
+static int _ncr_session_update_key(struct ncr_lists *lists,
+ struct session_item_st *sess,
+ struct nlattr *tb[]);
+
+static int session_list_deinit_fn(int id, void *item, void *unused)
+{
+ (void)unused;
+ _ncr_sessions_item_put(item);
+ return 0;
+}
+
+void ncr_sessions_list_deinit(struct ncr_lists *lst)
+{
+ /* The mutex is not necessary, but doesn't hurt and makes it easier to
+ verify locking correctness. */
+ mutex_lock(&lst->session_idr_mutex);
+ idr_for_each(&lst->session_idr, session_list_deinit_fn, NULL);
+ idr_remove_all(&lst->session_idr);
+ idr_destroy(&lst->session_idr);
+ mutex_unlock(&lst->session_idr_mutex);
+}
+
+/* Allocate a descriptor without making a sesssion available to userspace. */
+static ncr_session_t session_alloc_desc(struct ncr_lists *lst)
+{
+ int ret, desc;
+
+ mutex_lock(&lst->session_idr_mutex);
+ if (idr_pre_get(&lst->session_idr, GFP_KERNEL) == 0) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ /* idr_pre_get() should preallocate enough, and, due to
+ session_idr_mutex, nobody else can use the preallocated data.
+ Therefore the loop recommended in idr_get_new() documentation is not
+ necessary. */
+ ret = idr_get_new(&lst->session_idr, NULL, &desc);
+ if (ret != 0)
+ goto end;
+ ret = desc;
+end:
+ mutex_unlock(&lst->session_idr_mutex);
+ return ret;
+}
+
+/* Drop a pre-allocated, unpublished session descriptor */
+static void session_drop_desc(struct ncr_lists *lst, ncr_session_t desc)
+{
+ mutex_lock(&lst->session_idr_mutex);
+ idr_remove(&lst->session_idr, desc);
+ mutex_unlock(&lst->session_idr_mutex);
+}
+
+/* Make a session descriptor visible in user-space, stealing the reference */
+static void session_publish_ref(struct ncr_lists *lst,
+ struct session_item_st *sess)
+{
+ void *old;
+
+ mutex_lock(&lst->session_idr_mutex);
+ old = idr_replace(&lst->session_idr, sess, sess->desc);
+ mutex_unlock(&lst->session_idr_mutex);
+ BUG_ON(old != NULL);
+}
+
+/* returns the data item corresponding to desc */
+static struct session_item_st *session_get_ref(struct ncr_lists *lst,
+ ncr_session_t desc)
+{
+struct session_item_st* item;
+
+ mutex_lock(&lst->session_idr_mutex);
+ /* item may be NULL for pre-allocated session IDs. */
+ item = idr_find(&lst->session_idr, desc);
+ if (item != NULL) {
+ atomic_inc(&item->refcnt);
+ mutex_unlock(&lst->session_idr_mutex);
+ return item;
+ }
+ mutex_unlock(&lst->session_idr_mutex);
+
+ err();
+ return NULL;
+}
+
+/* Find a session, stealing the reference, but keep the descriptor allocated. */
+static struct session_item_st *session_unpublish_ref(struct ncr_lists *lst,
+ ncr_session_t desc)
+{
+ struct session_item_st *sess;
+
+ mutex_lock(&lst->session_idr_mutex);
+ /* sess may be NULL for pre-allocated session IDs. */
+ sess = idr_replace(&lst->session_idr, NULL, desc);
+ mutex_unlock(&lst->session_idr_mutex);
+ if (sess != NULL && !IS_ERR(sess))
+ return sess;
+
+ err();
+ return NULL;
+}
+
+static void _ncr_sessions_item_put(struct session_item_st *item)
+{
+ if (atomic_dec_and_test(&item->refcnt)) {
+ cryptodev_cipher_deinit(&item->cipher);
+ ncr_pk_cipher_deinit(&item->pk);
+ cryptodev_hash_deinit(&item->hash);
+ kfree(item->transparent_hash);
+ if (item->key)
+ _ncr_key_item_put(item->key);
+ kfree(item->sg);
+ kfree(item->pages);
+ kfree(item);
+ }
+}
+
+static struct session_item_st *ncr_session_new(ncr_session_t desc)
+{
+ struct session_item_st* sess;
+
+ sess = kzalloc(sizeof(*sess), GFP_KERNEL);
+ if (sess == NULL) {
+ err();
+ return NULL;
+ }
+
+ sess->array_size = DEFAULT_PREALLOC_PAGES;
+ sess->pages = kzalloc(sess->array_size *
+ sizeof(struct page *), GFP_KERNEL);
+ sess->sg = kzalloc(sess->array_size *
+ sizeof(struct scatterlist), GFP_KERNEL);
+ if (sess->sg == NULL || sess->pages == NULL) {
+ err();
+ goto err_sess;
+ }
+ mutex_init(&sess->mutex);
+
+ atomic_set(&sess->refcnt, 1);
+ sess->desc = desc;
+
+ return sess;
+
+err_sess:
+ kfree(sess->sg);
+ kfree(sess->pages);
+ kfree(sess);
+ return NULL;
+}
+
+const oid_st* _ncr_properties_to_oid(const struct algo_properties_st * prop, int key_size)
+{
+int i = 0;
+
+ if (prop->oids == NULL)
+ return NULL;
+
+ do {
+ if (key_size == prop->oids[i].key_size ||
+ prop->oids[i].key_size == -1 /* catch all */) {
+
+ return &prop->oids[i].oid;
+ }
+ } while(prop->oids[++i].key_size != 0);
+
+ return NULL;
+}
+
+const static struct algo_oid_st aes_cbc_oids[] = {
+ {.key_size=16,
+ .oid = {{2,16,840,1,101,3,4,1,2}, 9}},
+ {.key_size=24,
+ .oid = {{2,16,840,1,101,3,4,1,22}, 9}},
+ {.key_size=32,
+ .oid = {{2,16,840,1,101,3,4,1,42}, 9}},
+ {.key_size=0 }
+};
+
+const static struct algo_oid_st aes_ecb_oids[] = {
+ {.key_size=16,
+ .oid = {{2,16,840,1,101,3,4,1,1}, 9}},
+ {.key_size=24,
+ .oid = {{2,16,840,1,101,3,4,1,21}, 9}},
+ {.key_size=32,
+ .oid = {{2,16,840,1,101,3,4,1,41}, 9}},
+ {.key_size=0 }
+};
+
+const static struct algo_oid_st des3_cbc_oids[] = {
+ {.key_size=-1,
+ .oid = {{1,2,840,113549,3,7}, 6}},
+ {.key_size=0 }
+};
+
+/* http://www.oid-info.com/get/1.3.6.1.4.1.4929.1.7
+ */
+const static struct algo_oid_st des3_ecb_oids[] = {
+ {.key_size=-1,
+ .oid = {{1,3,6,1,4,1,4929,1,7}, 9}},
+ {.key_size=0 }
+};
+
+const static struct algo_oid_st camelia_cbc_oids[] = {
+ {.key_size=16,
+ .oid = {{1,2,392,200011,61,1,1,1,2}, 9}},
+ {.key_size=24,
+ .oid = {{1,2,392,200011,61,1,1,1,3}, 9}},
+ {.key_size=32,
+ .oid = {{1,2,392,200011,61,1,1,1,4}, 9}},
+ {.key_size=0 }
+};
+
+const static struct algo_oid_st rsa_oid[] = {
+ {.key_size=-1,
+ .oid = {{1,2,840,113549,1,1,1}, 7}},
+ {.key_size=0 }
+};
+
+const static struct algo_oid_st dsa_oid[] = {
+ {.key_size=-1,
+ .oid = {{1,2,840,10040,4,1}, 6}},
+ {.key_size=0 }
+};
+
+const static struct algo_oid_st dh_oid[] = {
+ {.key_size=-1,
+ .oid = {{1,2,840,10046,2,1}, 6}},
+ {.key_size=0 }
+};
+
+/* OIDs are used in cipher algorithms to distinguish keys on key wrapping.
+ */
+
+static const struct algo_properties_st algo_properties[] = {
+#define KSTR(x) .kstr = x, .kstr_len = sizeof(x) - 1
+ { .algo = NCR_ALG_NULL, KSTR("ecb(cipher_null)"),
+ .needs_iv = 0, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .algo = NCR_ALG_3DES_CBC, KSTR("cbc(des3_ede)"),
+ .needs_iv = 1, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, .oids = des3_cbc_oids },
+ { .algo = NCR_ALG_3DES_ECB, KSTR("ecb(des3_ede)"),
+ .needs_iv = 0, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, .oids = des3_ecb_oids },
+ { .algo = NCR_ALG_AES_CBC, KSTR("cbc(aes)"),
+ .needs_iv = 1, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, .oids = aes_cbc_oids },
+ { .algo = NCR_ALG_CAMELIA_CBC, KSTR("cbc(camelia)"),
+ .needs_iv = 1, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, .oids = camelia_cbc_oids },
+ { .algo = NCR_ALG_AES_CTR, KSTR("ctr(aes)"),
+ .needs_iv = 1, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, /* FIXME: no OIDs */ },
+ { .algo = NCR_ALG_CAMELIA_CTR, KSTR("ctr(camelia)"),
+ .needs_iv = 1, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, /* FIXME: no OIDs */ },
+ { .algo = NCR_ALG_AES_ECB, KSTR("ecb(aes)"),
+ .needs_iv = 0, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, .oids = aes_ecb_oids },
+ { .algo = NCR_ALG_CAMELIA_ECB, KSTR("ecb(camelia)"),
+ .needs_iv = 0, .is_symmetric=1, .can_encrypt=1,
+ .key_type = NCR_KEY_TYPE_SECRET, /* FIXME: no OIDs */ },
+ { .algo = NCR_ALG_SHA1, KSTR("sha1"),
+ .digest_size = 20, .can_digest=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .algo = NCR_ALG_MD5, KSTR("md5"),
+ .digest_size = 16, .can_digest=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .algo = NCR_ALG_SHA2_224, KSTR("sha224"),
+ .digest_size = 28, .can_digest=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .algo = NCR_ALG_SHA2_256, KSTR("sha256"),
+ .digest_size = 32, .can_digest=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .algo = NCR_ALG_SHA2_384, KSTR("sha384"),
+ .digest_size = 48, .can_digest=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .algo = NCR_ALG_SHA2_512, KSTR("sha512"),
+ .digest_size = 64, .can_digest=1,
+ .key_type = NCR_KEY_TYPE_INVALID },
+ { .is_hmac = 1, KSTR("hmac(sha1)"),
+ .digest_size = 20, .can_sign=1,
+ .key_type = NCR_KEY_TYPE_SECRET },
+ { .is_hmac = 1, KSTR("hmac(md5)"),
+ .digest_size = 16, .can_sign=1,
+ .key_type = NCR_KEY_TYPE_SECRET },
+ { .is_hmac = 1, KSTR("hmac(sha224)"),
+ .digest_size = 28, .can_sign=1,
+ .key_type = NCR_KEY_TYPE_SECRET },
+ { .is_hmac = 1, KSTR("hmac(sha256)"),
+ .digest_size = 32, .can_sign=1,
+ .key_type = NCR_KEY_TYPE_SECRET },
+ { .is_hmac = 1, KSTR("hmac(sha384)"),
+ .digest_size = 48, .can_sign=1,
+ .key_type = NCR_KEY_TYPE_SECRET },
+ { .is_hmac = 1, KSTR("hmac(sha512)"),
+ .digest_size = 64, .can_sign=1,
+ .key_type = NCR_KEY_TYPE_SECRET },
+ /* NOTE: These algorithm names are not available through the kernel API
+ (yet). */
+ { .algo = NCR_ALG_RSA, KSTR("rsa"), .is_pk = 1,
+ .can_encrypt=1, .can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC,
+ .oids = rsa_oid },
+ { .algo = NCR_ALG_DSA, KSTR("dsa"), .is_pk = 1,
+ .can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC,
+ .oids = dsa_oid },
+ { .algo = NCR_ALG_DH, KSTR("dh"), .is_pk = 1,
+ .can_kx=1, .key_type = NCR_KEY_TYPE_PUBLIC,
+ .oids = dh_oid },
+
+ { .algo = NCR_ALG_DSA, KSTR(NCR_ALG_DSA_TRANSPARENT_HASH), .is_pk = 1,
+ .can_sign=1, .has_transparent_hash = 1,
+ .key_type = NCR_KEY_TYPE_PUBLIC, .oids = rsa_oid },
+ { .algo = NCR_ALG_RSA, KSTR(NCR_ALG_RSA_TRANSPARENT_HASH), .is_pk = 1,
+ .can_encrypt=1, .can_sign=1, .has_transparent_hash = 1,
+ .key_type = NCR_KEY_TYPE_PUBLIC, .oids = dsa_oid },
+
+#undef KSTR
+};
+
+/* The lookups by string are inefficient - can we look up all we need from
+ crypto API? */
+const struct algo_properties_st *_ncr_algo_to_properties(ncr_algorithm_t algo)
+{
+ const struct algo_properties_st *a;
+
+ for (a = algo_properties;
+ a < algo_properties + ARRAY_SIZE(algo_properties); a++) {
+ if (a->algo == algo)
+ return a;
+ }
+
+ return NULL;
+}
+
+static void print_oid(oid_st* oid)
+{
+char txt[128]="";
+char tmp[64];
+int i;
+
+ for (i=0;i<oid->OIDlen;i++) {
+ sprintf(tmp, "%d.", (int)oid->OID[i]);
+ strcat(txt, tmp);
+ }
+
+ dprintk(1, KERN_DEBUG, "unknown oid: %s\n", txt);
+}
+
+const struct algo_properties_st *_ncr_oid_to_properties(oid_st* oid)
+{
+ const struct algo_properties_st *a;
+ int i;
+
+ for (a = algo_properties;
+ a < algo_properties + ARRAY_SIZE(algo_properties); a++) {
+
+ i=0;
+
+ if (a->oids == NULL) continue;
+
+ do {
+ if (a->oids[i].oid.OIDlen == oid->OIDlen &&
+ memcmp(oid->OID, a->oids[i].oid.OID, oid->OIDlen*sizeof(oid->OID[0]))==0)
+ return a;
+ } while(a->oids[++i].key_size != 0);
+ }
+
+ print_oid(oid);
+ return NULL;
+}
+
+const struct algo_properties_st *_ncr_nla_to_properties(const struct nlattr *nla)
+{
+ const struct algo_properties_st *a;
+ size_t name_len;
+
+ if (nla == NULL)
+ return NULL;
+
+ /* nla_len() >= 1 ensured by validate_nla() case NLA_NUL_STRING */
+ name_len = nla_len(nla) - 1;
+ for (a = algo_properties;
+ a < algo_properties + ARRAY_SIZE(algo_properties); a++) {
+ if (a->kstr_len == name_len
+ && memcmp(a->kstr, nla_data(nla), name_len + 1) == 0)
+ return a;
+ }
+ return NULL;
+}
+
+static const char *ncr_op_name(ncr_crypto_op_t op)
+{
+ static const char *const names[] = {
+ [NCR_OP_ENCRYPT] = "encrypt",
+ [NCR_OP_DECRYPT] = "decrypt",
+ [NCR_OP_SIGN] = "sign",
+ [NCR_OP_VERIFY] = "verify"
+ };
+
+ const char *res;
+
+ res = NULL;
+ if (op < ARRAY_SIZE(names))
+ res = names[op];
+ if (res == NULL)
+ res = "unknown";
+ return res;
+}
+
+const char *ncr_algorithm_name(const struct algo_properties_st *algo)
+{
+ if (algo != NULL && algo->kstr != NULL)
+ return algo->kstr;
+ return "unknown";
+}
+
+static int key_item_get_nla_read(struct key_item_st **st,
+ struct ncr_lists *lists,
+ const struct nlattr *nla)
+{
+ int ret;
+
+ if (nla == NULL) {
+ err();
+ return -EINVAL;
+ }
+ ret = ncr_key_item_get_read(st, lists, nla_get_u32(nla));
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ return ret;
+}
+
+/* The caller is responsible for locking of "session". old_session must not be
+ locked on entry. */
+static int
+init_or_clone_hash(struct session_item_st *session,
+ struct session_item_st *old_session,
+ const struct algo_properties_st *algo,
+ const void *mac_key, size_t mac_key_size)
+{
+ int ret;
+
+ if (old_session == NULL)
+ return cryptodev_hash_init(&session->hash, algo->kstr,
+ mac_key, mac_key_size);
+
+ if (mutex_lock_interruptible(&old_session->mutex)) {
+ err();
+ return -ERESTARTSYS;
+ }
+ ret = cryptodev_hash_clone(&session->hash, &old_session->hash, mac_key,
+ mac_key_size);
+ mutex_unlock(&old_session->mutex);
+
+ return ret;
+}
+
+static struct session_item_st *_ncr_session_init(struct ncr_lists *lists,
+ ncr_session_t desc,
+ ncr_crypto_op_t op,
+ struct nlattr *tb[])
+{
+ const struct nlattr *nla;
+ struct session_item_st *ns, *old_session = NULL;
+ int ret;
+ const struct algo_properties_st *sign_hash;
+
+ ns = ncr_session_new(desc);
+ if (ns == NULL) {
+ err();
+ return ERR_PTR(-ENOMEM);
+ }
+ /* ns is the only reference throughout this function, so no locking
+ is necessary. */
+
+ ns->op = op;
+ nla = tb[NCR_ATTR_SESSION_CLONE_FROM];
+ if (nla != NULL) {
+ /* "ns" is not visible to userspace, so this is safe. */
+ old_session = session_get_ref(lists, nla_get_u32(nla));
+ if (old_session == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (ns->op != old_session->op) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
+ if (old_session == NULL) {
+ ns->algorithm = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]);
+ if (ns->algorithm == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ } else
+ ns->algorithm = old_session->algorithm;
+
+ switch(op) {
+ case NCR_OP_ENCRYPT:
+ case NCR_OP_DECRYPT:
+ if (!ns->algorithm->can_encrypt) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (old_session != NULL) {
+ err();
+ ret = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ /* read key */
+ ret = key_item_get_nla_read(&ns->key, lists,
+ tb[NCR_ATTR_KEY]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ /* wrapping keys cannot be used for encryption or decryption
+ */
+ if (ns->key->flags & NCR_KEY_FLAG_WRAPPING || ns->key->flags & NCR_KEY_FLAG_UNWRAPPING) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (ns->key->type == NCR_KEY_TYPE_SECRET) {
+ int keysize = ns->key->key.secret.size;
+
+ if (ns->algorithm->algo == NCR_ALG_NULL)
+ keysize = 0;
+
+ if (ns->algorithm->is_pk) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = cryptodev_cipher_init(&ns->cipher, ns->algorithm->kstr,
+ ns->key->key.secret.data, keysize);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ if (ns->algorithm->needs_iv) {
+ nla = tb[NCR_ATTR_IV];
+ if (nla == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ cryptodev_cipher_set_iv(&ns->cipher,
+ nla_data(nla),
+ nla_len(nla));
+ }
+ } else if (ns->key->type == NCR_KEY_TYPE_PRIVATE || ns->key->type == NCR_KEY_TYPE_PUBLIC) {
+ ret = ncr_pk_cipher_init(ns->algorithm, &ns->pk,
+ tb, ns->key, NULL);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ } else {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ break;
+
+ case NCR_OP_SIGN:
+ case NCR_OP_VERIFY:
+ if (!ns->algorithm->can_sign && !ns->algorithm->can_digest) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (ns->algorithm->can_digest) {
+ if (ns->algorithm->is_pk) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = init_or_clone_hash(ns, old_session,
+ ns->algorithm, NULL,
+ 0);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ } else {
+ /* Get key */
+ if (old_session == NULL) {
+ ret = key_item_get_nla_read(&ns->key,
+ lists,
+ tb[NCR_ATTR_KEY]);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ } else {
+ atomic_inc(&old_session->key->refcnt);
+ ns->key = old_session->key;
+ }
+
+ /* wrapping keys cannot be used for anything except wrapping.
+ */
+ if (ns->key->flags & NCR_KEY_FLAG_WRAPPING || ns->key->flags & NCR_KEY_FLAG_UNWRAPPING) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* wrapping keys cannot be used for anything except wrapping.
+ */
+ if (ns->key->flags & NCR_KEY_FLAG_WRAPPING) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (ns->algorithm->is_hmac && ns->key->type == NCR_KEY_TYPE_SECRET) {
+ if (ns->algorithm->is_pk) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = init_or_clone_hash(ns, old_session, ns->algorithm,
+ ns->key->key.secret.data, ns->key->key.secret.size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ } else if (ns->algorithm->is_pk && (ns->key->type == NCR_KEY_TYPE_PRIVATE || ns->key->type == NCR_KEY_TYPE_PUBLIC)) {
+ if (old_session != NULL) {
+ err();
+ ret = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ nla = tb[NCR_ATTR_SIGNATURE_HASH_ALGORITHM];
+ sign_hash = _ncr_nla_to_properties(nla);
+ if (sign_hash == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!sign_hash->can_digest) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (sign_hash->is_pk) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = ncr_pk_cipher_init(ns->algorithm, &ns->pk,
+ tb, ns->key, sign_hash);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = cryptodev_hash_init(&ns->hash, sign_hash->kstr, NULL, 0);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ if (ns->algorithm->has_transparent_hash) {
+ /* transparent hash has to be allowed by the key
+ */
+ if (!(ns->key->flags & NCR_KEY_FLAG_ALLOW_TRANSPARENT_HASH)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ ns->transparent_hash = kzalloc(ns->hash.digestsize, GFP_KERNEL);
+ if (ns->transparent_hash == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
+ } else {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_INIT, lists->id,
+ ns->desc, ncr_op_name(ns->op),
+ ncr_algorithm_name(ns->algorithm),
+ ns->key != NULL ? ns->key->desc : -1,
+ ns->key != NULL ? ns->key->key_id : NULL,
+ ns->key != NULL ? ns->key->key_id_size : 0,
+ -1, NULL, 0);
+ if (ret != 0)
+ goto fail_noaudit;
+
+ if (old_session != NULL)
+ _ncr_sessions_item_put(old_session);
+
+ return ns;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_INIT, lists->id, ns->desc,
+ ncr_op_name(ns->op),
+ ncr_algorithm_name(ns->algorithm),
+ ns->key != NULL ? ns->key->desc : -1,
+ ns->key != NULL ? ns->key->key_id : NULL,
+ ns->key != NULL ? ns->key->key_id_size : 0, -1,
+ NULL, 0);
+fail_noaudit:
+ if (old_session != NULL)
+ _ncr_sessions_item_put(old_session);
+ _ncr_sessions_item_put(ns);
+
+ return ERR_PTR(ret);
+}
+
+int ncr_session_init(struct ncr_lists *lists,
+ const struct ncr_session_init *session,
+ struct nlattr *tb[])
+{
+ ncr_session_t desc;
+ struct session_item_st *sess;
+
+ desc = session_alloc_desc(lists);
+ if (desc < 0) {
+ err();
+ return desc;
+ }
+
+ sess = _ncr_session_init(lists, desc, session->op, tb);
+ if (IS_ERR(sess)) {
+ err();
+ session_drop_desc(lists, desc);
+ return PTR_ERR(sess);
+ }
+
+ session_publish_ref(lists, sess);
+
+ return desc;
+}
+
+/* The caller is responsible for locking of the session. */
+static int _ncr_session_encrypt(struct session_item_st* sess, const struct scatterlist* input, unsigned input_cnt,
+ size_t input_size, void *output, unsigned output_cnt, size_t *output_size)
+{
+int ret;
+
+ if (sess->algorithm->is_symmetric) {
+ /* read key */
+ ret = cryptodev_cipher_encrypt(&sess->cipher, input,
+ output, input_size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ /* FIXME: handle ciphers that do not require that */
+ *output_size = input_size;
+ } else { /* public key */
+ ret = ncr_pk_cipher_encrypt(&sess->pk, input, input_cnt, input_size,
+ output, output_cnt, output_size);
+
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* The caller is responsible for locking of the session. */
+static int _ncr_session_decrypt(struct session_item_st* sess, const struct scatterlist* input,
+ unsigned input_cnt, size_t input_size,
+ struct scatterlist *output, unsigned output_cnt, size_t *output_size)
+{
+int ret;
+
+ if (sess->algorithm->is_symmetric) {
+ /* read key */
+ ret = cryptodev_cipher_decrypt(&sess->cipher, input,
+ output, input_size);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ /* FIXME: handle ciphers that do not require equality */
+ *output_size = input_size;
+ } else { /* public key */
+ ret = ncr_pk_cipher_decrypt(&sess->pk, input, input_cnt, input_size,
+ output, output_cnt, output_size);
+
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* The caller is responsible for locking of the session. */
+static int _ncr_session_grow_pages(struct session_item_st *ses, int pagecount)
+{
+ struct scatterlist *sg;
+ struct page **pages;
+ int array_size;
+
+ if (likely(pagecount < ses->array_size))
+ return 0;
+
+ for (array_size = ses->array_size; array_size < pagecount;
+ array_size *= 2)
+ ;
+
+ dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n",
+ __func__, array_size);
+ pages = krealloc(ses->pages, array_size * sizeof(struct page *),
+ GFP_KERNEL);
+ if (unlikely(pages == NULL))
+ return -ENOMEM;
+ ses->pages = pages;
+ sg = krealloc(ses->sg, array_size * sizeof(struct scatterlist),
+ GFP_KERNEL);
+ if (unlikely(sg == NULL))
+ return -ENOMEM;
+ ses->sg = sg;
+
+ ses->array_size = array_size;
+ return 0;
+}
+
+/* Make NCR_ATTR_UPDATE_INPUT_DATA and NCR_ATTR_UPDATE_OUTPUT_BUFFER available
+ in scatterlists.
+ The caller is responsible for locking of the session. */
+static int get_userbuf2(struct session_item_st *ses, struct nlattr *tb[],
+ struct scatterlist **src_sg, unsigned *src_cnt,
+ size_t *src_size, struct ncr_session_output_buffer *dst,
+ struct scatterlist **dst_sg, unsigned *dst_cnt,
+ int compat)
+{
+ const struct nlattr *src_nla, *dst_nla;
+ struct ncr_session_input_data src;
+ int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1, ret;
+ size_t input_size;
+
+ src_nla = tb[NCR_ATTR_UPDATE_INPUT_DATA];
+ dst_nla = tb[NCR_ATTR_UPDATE_OUTPUT_BUFFER];
+
+ ret = ncr_session_input_data_from_nla(&src, src_nla, compat);
+ if (unlikely(ret != 0)) {
+ err();
+ return ret;
+ }
+ *src_size = src.data_size;
+
+ if (dst_nla != NULL) {
+ ret = ncr_session_output_buffer_from_nla(dst, dst_nla, compat);
+ if (unlikely(ret != 0)) {
+ err();
+ return ret;
+ }
+ }
+
+ input_size = src.data_size;
+ src_pagecount = PAGECOUNT(src.data, input_size);
+
+ if (dst_nla == NULL || src.data != dst->buffer) { /* non-in-situ transformation */
+ write_src = 0;
+ if (dst_nla != NULL) {
+ dst_pagecount = PAGECOUNT(dst->buffer,
+ dst->buffer_size);
+ } else {
+ dst_pagecount = 0;
+ }
+ } else {
+ src_pagecount = max((int)(PAGECOUNT(dst->buffer,
+ dst->buffer_size)),
+ src_pagecount);
+ input_size = max(input_size, dst->buffer_size);
+ }
+
+ pagecount = src_pagecount + dst_pagecount;
+ ret = _ncr_session_grow_pages(ses, pagecount);
+ if (ret != 0) {
+ err();
+ return ret;
+ }
+
+ if (__get_userbuf((void __user *)src.data, input_size, write_src,
+ src_pagecount, ses->pages, ses->sg)) {
+ err();
+ printk("write: %d\n", write_src);
+ return -EINVAL;
+ }
+ (*src_sg) = ses->sg;
+ *src_cnt = src_pagecount;
+
+ if (dst_pagecount) {
+ *dst_cnt = dst_pagecount;
+ (*dst_sg) = ses->sg + src_pagecount;
+
+ if (__get_userbuf(dst->buffer, dst->buffer_size, 1,
+ dst_pagecount, ses->pages + src_pagecount,
+ *dst_sg)) {
+ err();
+ release_user_pages(ses->pages, src_pagecount);
+ return -EINVAL;
+ }
+ } else {
+ if (dst_nla != NULL) {
+ *dst_cnt = src_pagecount;
+ (*dst_sg) = (*src_sg);
+ } else {
+ *dst_cnt = 0;
+ *dst_sg = NULL;
+ }
+ }
+
+ ses->available_pages = pagecount;
+
+ return 0;
+}
+
+/* Called when userspace buffers are used.
+ The caller is responsible for locking of the session. */
+static int _ncr_session_update(struct ncr_lists *lists,
+ struct session_item_st *sess,
+ struct nlattr *tb[], int compat)
+{
+ const struct nlattr *nla;
+ int ret;
+ struct scatterlist *isg = NULL;
+ struct scatterlist *osg = NULL;
+ unsigned osg_cnt=0, isg_cnt=0;
+ size_t isg_size = 0, osg_size;
+ struct ncr_session_output_buffer out;
+
+ ret = get_userbuf2(sess, tb, &isg, &isg_cnt, &isg_size, &out, &osg,
+ &osg_cnt, compat);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ switch(sess->op) {
+ case NCR_OP_ENCRYPT:
+ if (osg == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ osg_size = out.buffer_size;
+ if (osg_size < isg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (sess->algorithm->is_symmetric
+ && sess->algorithm->needs_iv) {
+ nla = tb[NCR_ATTR_IV];
+ if (nla != NULL)
+ cryptodev_cipher_set_iv(&sess->cipher,
+ nla_data(nla),
+ nla_len(nla));
+ }
+
+ ret = _ncr_session_encrypt(sess, isg, isg_cnt, isg_size,
+ osg, osg_cnt, &osg_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = ncr_session_output_buffer_set_size(&out, osg_size,
+ compat);
+ if (ret != 0) {
+ err();
+ goto fail;
+ }
+ break;
+ case NCR_OP_DECRYPT:
+ if (osg == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ osg_size = out.buffer_size;
+ if (osg_size < isg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (sess->algorithm->is_symmetric
+ && sess->algorithm->needs_iv) {
+ nla = tb[NCR_ATTR_IV];
+ if (nla != NULL)
+ cryptodev_cipher_set_iv(&sess->cipher,
+ nla_data(nla),
+ nla_len(nla));
+ }
+
+ ret = _ncr_session_decrypt(sess, isg, isg_cnt, isg_size,
+ osg, osg_cnt, &osg_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = ncr_session_output_buffer_set_size(&out, osg_size,
+ compat);
+ if (ret != 0) {
+ err();
+ goto fail;
+ }
+ break;
+
+ case NCR_OP_SIGN:
+ case NCR_OP_VERIFY:
+ if (sess->algorithm->has_transparent_hash) {
+ if (isg_size != sess->hash.digestsize) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ ret = sg_copy_to_buffer(isg, isg_cnt,
+ sess->transparent_hash,
+ isg_size);
+ if (ret != isg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ } else {
+ ret = cryptodev_hash_update(&sess->hash, isg,
+ isg_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ }
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_OP, lists->id, sess->desc,
+ ncr_op_name(sess->op),
+ ncr_algorithm_name(sess->algorithm), -1, NULL, 0,
+ -1, NULL, 0);
+
+ if (sess->available_pages) {
+ release_user_pages(sess->pages, sess->available_pages);
+ sess->available_pages = 0;
+ }
+
+ return ret;
+}
+
+/* The caller is responsible for locking of the session. */
+static int try_session_update(struct ncr_lists *lists,
+ struct session_item_st *sess, struct nlattr *tb[],
+ int compat)
+{
+ if (tb[NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA] != NULL)
+ return _ncr_session_update_key(lists, sess, tb);
+ else if (tb[NCR_ATTR_UPDATE_INPUT_DATA] != NULL)
+ return _ncr_session_update(lists, sess, tb, compat);
+ else
+ return 0;
+}
+
+/* The caller is responsible for locking of the session.
+ Note that one or more _ncr_session_update()s may still be blocked on
+ sess->mutex and will execute after this function! */
+static int _ncr_session_final(struct ncr_lists *lists,
+ struct session_item_st *sess, struct nlattr *tb[],
+ int compat)
+{
+ const struct nlattr *nla;
+ int ret;
+ int digest_size;
+ uint8_t digest[NCR_HASH_MAX_OUTPUT_SIZE];
+ void *buffer = NULL;
+
+ ret = try_session_update(lists, sess, tb, compat);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ switch(sess->op) {
+ case NCR_OP_ENCRYPT:
+ case NCR_OP_DECRYPT:
+ break;
+ case NCR_OP_VERIFY: {
+ struct ncr_session_input_data src;
+
+ nla = tb[NCR_ATTR_FINAL_INPUT_DATA];
+ ret = ncr_session_input_data_from_nla(&src, nla, compat);
+ if (unlikely(ret != 0)) {
+ err();
+ goto fail;
+ }
+
+ buffer = kmalloc(src.data_size, GFP_KERNEL);
+ if (buffer == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+ if (unlikely(copy_from_user(buffer, src.data, src.data_size))) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ digest_size = sess->hash.digestsize;
+ if (digest_size == 0 || sizeof(digest) < digest_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (sess->algorithm->has_transparent_hash)
+ memcpy(digest, sess->transparent_hash, digest_size);
+ else {
+ ret = cryptodev_hash_final(&sess->hash, digest);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ }
+
+ if (!sess->algorithm->is_pk)
+ ret = (digest_size == src.data_size
+ && memcmp(buffer, digest, digest_size) == 0);
+ else {
+ ret = ncr_pk_cipher_verify(&sess->pk, buffer,
+ src.data_size, digest,
+ digest_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ }
+ break;
+ }
+
+ case NCR_OP_SIGN: {
+ struct ncr_session_output_buffer dst;
+ size_t output_size;
+
+ nla = tb[NCR_ATTR_FINAL_OUTPUT_BUFFER];
+ ret = ncr_session_output_buffer_from_nla(&dst, nla, compat);
+ if (unlikely(ret != 0)) {
+ err();
+ goto fail;
+ }
+
+ digest_size = sess->hash.digestsize;
+ if (digest_size == 0) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (sess->algorithm->has_transparent_hash)
+ memcpy(digest, sess->transparent_hash, digest_size);
+ else {
+ ret = cryptodev_hash_final(&sess->hash, digest);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ }
+
+ cryptodev_hash_deinit(&sess->hash);
+
+ if (!sess->algorithm->is_pk) {
+ if (dst.buffer_size < digest_size) {
+ err();
+ ret = -ERANGE;
+ goto fail;
+ }
+ if (unlikely(copy_to_user(dst.buffer, digest,
+ digest_size))) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+ output_size = digest_size;
+ } else {
+ output_size = dst.buffer_size;
+ buffer = kmalloc(output_size, GFP_KERNEL);
+ if (buffer == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+ ret = ncr_pk_cipher_sign(&sess->pk, digest, digest_size,
+ buffer, &output_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ if (unlikely(copy_to_user(dst.buffer, buffer,
+ output_size))) {
+ err();
+ ret = -EFAULT;
+ goto fail;
+ }
+ }
+
+ ret = ncr_session_output_buffer_set_size(&dst, output_size,
+ compat);
+ if (ret != 0) {
+ err();
+ goto fail;
+ }
+ break;
+ }
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+fail:
+ kfree(buffer);
+
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_FINAL, lists->id,
+ sess->desc, ncr_op_name(sess->op),
+ ncr_algorithm_name(sess->algorithm), -1, NULL, 0,
+ -1, NULL, 0);
+
+ return ret;
+}
+
+/* Direct with key: Allows to hash a key.
+ The caller is responsible for locking of the session. */
+static int _ncr_session_update_key(struct ncr_lists *lists,
+ struct session_item_st* sess,
+ struct nlattr *tb[])
+{
+ int ret;
+ struct key_item_st* key = NULL;
+
+ /* read key */
+ ret = key_item_get_nla_read(&key, lists,
+ tb[NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA]);
+ if (ret < 0) {
+ err();
+ return ret;
+ }
+
+ if (key->type != NCR_KEY_TYPE_SECRET) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!(key->flags & NCR_KEY_FLAG_HASHABLE)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ switch(sess->op) {
+ case NCR_OP_ENCRYPT:
+ case NCR_OP_DECRYPT:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ case NCR_OP_SIGN:
+ case NCR_OP_VERIFY:
+ if (sess->algorithm->has_transparent_hash) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ ret = _cryptodev_hash_update(&sess->hash,
+ key->key.secret.data, key->key.secret.size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_OP, lists->id, sess->desc,
+ ncr_op_name(sess->op),
+ ncr_algorithm_name(sess->algorithm), key->desc,
+ key->key_id, key->key_id_size, -1, NULL, 0);
+
+ _ncr_key_item_put(key);
+
+ return ret;
+}
+
+int ncr_session_update(struct ncr_lists *lists,
+ const struct ncr_session_update *op, struct nlattr *tb[],
+ int compat)
+{
+ struct session_item_st *sess;
+ int ret;
+
+ sess = session_get_ref(lists, op->ses);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ /* Note that op->ses may be reallocated from now on, making the audit
+ information confusing. */
+
+ if (mutex_lock_interruptible(&sess->mutex)) {
+ err();
+ ret = -ERESTARTSYS;
+ goto end;
+ }
+ if (tb[NCR_ATTR_UPDATE_INPUT_DATA] != NULL)
+ ret = _ncr_session_update(lists, sess, tb, compat);
+ else if (tb[NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA] != NULL)
+ ret = _ncr_session_update_key(lists, sess, tb);
+ else
+ ret = -EINVAL;
+ mutex_unlock(&sess->mutex);
+
+end:
+ _ncr_sessions_item_put(sess);
+
+ if (unlikely(ret)) {
+ err();
+ return ret;
+ }
+
+ return 0;
+}
+
+int ncr_session_final(struct ncr_lists *lists,
+ const struct ncr_session_final *op, struct nlattr *tb[],
+ int compat)
+{
+ struct session_item_st *sess;
+ int ret;
+
+ /* Make the session inaccessible atomically to avoid concurrent
+ session_final() callers, but keep the ID allocated to keep audit
+ information unambiguous. */
+ sess = session_unpublish_ref(lists, op->ses);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&sess->mutex)) {
+ err();
+ /* Other threads may observe the session descriptor
+ disappearing and reappearing - but then they should not be
+ accessing it anyway if it is being freed.
+ session_unpublish_ref keeps the ID allocated for us. */
+ session_publish_ref(lists, sess);
+ return -ERESTARTSYS;
+ }
+ ret = _ncr_session_final(lists, sess, tb, compat);
+ mutex_unlock(&sess->mutex);
+
+ _ncr_sessions_item_put(sess);
+ session_drop_desc(lists, op->ses);
+
+ return ret;
+}
+
+int ncr_session_once(struct ncr_lists *lists,
+ const struct ncr_session_once *once, struct nlattr *tb[],
+ int compat)
+{
+ struct session_item_st *sess;
+ int ret;
+
+ sess = _ncr_session_init(lists, -1, once->op, tb);
+ if (IS_ERR(sess)) {
+ err();
+ return PTR_ERR(sess);
+ }
+
+ /* No locking of sess necessary, "sess" is the only reference. */
+ ret = _ncr_session_final(lists, sess, tb, compat);
+
+ _ncr_sessions_item_put(sess);
+
+ return ret;
+}
diff --git a/crypto/userspace/ncr.c b/crypto/userspace/ncr.c
new file mode 100644
index 00000000000..01ad1703c58
--- /dev/null
+++ b/crypto/userspace/ncr.c
@@ -0,0 +1,519 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/audit.h>
+#include <linux/compat.h>
+#include <linux/crypto.h>
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/highmem.h>
+#include <linux/random.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include <linux/cred.h>
+#include <linux/capability.h>
+#include <linux/ncr.h>
+#include <net/netlink.h>
+#include "ncr-int.h"
+#include "utils.h"
+#include <linux/workqueue.h>
+
+/* This is the master wrapping key for storage of keys
+ */
+struct key_item_st master_key;
+
+static struct mutex lists_ida_mutex;
+static DEFINE_IDA(lists_ida);
+
+struct ncr_lists *ncr_init_lists(void)
+{
+ struct ncr_lists *lst;
+
+ lst = kmalloc(sizeof(*lst), GFP_KERNEL);
+ if(!lst) {
+ err();
+ return NULL;
+ }
+
+ memset(lst, 0, sizeof(*lst));
+
+ mutex_init(&lists_ida_mutex);
+ mutex_lock(&lists_ida_mutex);
+ /* ida_pre_get() should preallocate enough, and, due to lists_ida_mutex,
+ nobody else can use the preallocated data. Therefore the loop
+ recommended in idr_get_new() documentation is not necessary. */
+ if (ida_pre_get(&lists_ida, GFP_KERNEL) == 0 ||
+ ida_get_new(&lists_ida, &lst->id) != 0) {
+ mutex_unlock(&lists_ida_mutex);
+ kfree(lst);
+ return NULL;
+ }
+ mutex_unlock(&lists_ida_mutex);
+
+ mutex_init(&lst->key_idr_mutex);
+ idr_init(&lst->key_idr);
+
+ mutex_init(&lst->session_idr_mutex);
+ idr_init(&lst->session_idr);
+
+ return lst;
+}
+
+void ncr_deinit_lists(struct ncr_lists *lst)
+{
+ if(lst) {
+ ncr_key_list_deinit(lst);
+ ncr_sessions_list_deinit(lst);
+
+ mutex_lock(&lists_ida_mutex);
+ ida_remove(&lists_ida, lst->id);
+ mutex_unlock(&lists_ida_mutex);
+
+ kfree(lst);
+ }
+}
+
+void ncr_master_key_reset(void)
+{
+ memset(&master_key, 0, sizeof(master_key));
+}
+
+static int ncr_master_key_set(const struct ncr_master_key_set *st,
+ struct nlattr *tb[])
+{
+ struct audit_buffer *ab;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ err();
+ return -EPERM;
+ }
+
+ /* This will also cause auditing of the syscall, including information
+ about the process, and success/failure indication. Note that on
+ error the AUDIT_CRYPTO_STORAGE_KEY record will be empty. */
+ ab = audit_log_start(current->audit_context, GFP_KERNEL,
+ AUDIT_CRYPTO_STORAGE_KEY);
+
+ if (st->key_size > sizeof(master_key.key.secret.data)) {
+ err();
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (st->key_size != 16 && st->key_size != 24 && st->key_size != 32) {
+ dprintk(0, KERN_DEBUG, "Master key size must be 16,24 or 32.\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (master_key.type != NCR_KEY_TYPE_INVALID) {
+ dprintk(0, KERN_DEBUG, "Master key was previously initialized.\n");
+ }
+
+ if (unlikely(copy_from_user(master_key.key.secret.data, st->key,
+ st->key_size))) {
+ err();
+ ret = -EFAULT;
+ goto end;
+ }
+
+ dprintk(0, KERN_INFO, "Initializing master key.\n");
+ /* Not much we can reveal... */
+ audit_log_format(ab, "key_size=%u", (unsigned)st->key_size);
+
+ master_key.type = NCR_KEY_TYPE_SECRET;
+ master_key.key.secret.size = st->key_size;
+
+ ret = 0;
+
+end:
+ audit_log_end(ab);
+
+ return ret;
+}
+
+long
+ncr_ioctl(struct ncr_lists *lst, unsigned int cmd, unsigned long arg_)
+{
+ void __user *arg = (void __user *)arg_;
+ struct nlattr *tb[NCR_ATTR_MAX + 1];
+ void *attr_buf;
+ int ret;
+
+ if (unlikely(!lst))
+ BUG();
+
+ switch (cmd) {
+#define CASE_(LABEL, STRUCT, FUNCTION, ARGS) \
+ case (LABEL): { \
+ struct STRUCT data; \
+ \
+ attr_buf = NCR_GET_INPUT_ARGS_NO_OUTPUT(&data, tb, arg); \
+ if (IS_ERR(attr_buf)) { \
+ err(); \
+ return PTR_ERR(attr_buf); \
+ } \
+ ret = (FUNCTION)ARGS; \
+ break; \
+ }
+#define CASE_NO_OUTPUT(LABEL, STRUCT, FUNCTION) \
+ CASE_(LABEL, STRUCT, FUNCTION, (lst, &data, tb))
+#define CASE_NO_OUTPUT_COMPAT(LABEL, STRUCT, FUNCTION) \
+ CASE_(LABEL, STRUCT, FUNCTION, (lst, &data, tb, 0))
+
+ case NCRIO_KEY_INIT:
+ return ncr_key_init(lst);
+ CASE_NO_OUTPUT(NCRIO_KEY_GENERATE, ncr_key_generate, ncr_key_generate);
+ CASE_NO_OUTPUT(NCRIO_KEY_GENERATE_PAIR, ncr_key_generate_pair,
+ ncr_key_generate_pair);
+ CASE_NO_OUTPUT(NCRIO_KEY_DERIVE, ncr_key_derive, ncr_key_derive);
+ case NCRIO_KEY_GET_INFO: {
+ struct ncr_key_get_info data;
+ struct ncr_out out;
+
+ attr_buf = NCR_GET_INPUT_ARGS(&data, tb, arg);
+ if (IS_ERR(attr_buf)) {
+ err();
+ return PTR_ERR(attr_buf);
+ }
+ ret = NCR_OUT_INIT(&out, &data, arg);
+ if (ret != 0) {
+ err();
+ break;
+ }
+ ret = ncr_key_get_info(lst, &out, &data, tb);
+ ncr_out_free(&out);
+ break;
+ }
+ CASE_NO_OUTPUT(NCRIO_KEY_EXPORT, ncr_key_export, ncr_key_export);
+ CASE_NO_OUTPUT(NCRIO_KEY_IMPORT, ncr_key_import, ncr_key_import);
+ case NCRIO_KEY_DEINIT: {
+ ncr_key_t key;
+
+ ret = get_user(key, (const ncr_key_t __user *)arg);
+ if (unlikely(ret)) {
+ err();
+ return ret;
+ }
+ return ncr_key_deinit(lst, key);
+ }
+ CASE_NO_OUTPUT(NCRIO_KEY_WRAP, ncr_key_wrap, ncr_key_wrap);
+ CASE_NO_OUTPUT(NCRIO_KEY_UNWRAP, ncr_key_unwrap, ncr_key_unwrap);
+ CASE_NO_OUTPUT(NCRIO_KEY_STORAGE_WRAP, ncr_key_storage_wrap,
+ ncr_key_storage_wrap);
+ CASE_NO_OUTPUT(NCRIO_KEY_STORAGE_UNWRAP, ncr_key_storage_unwrap,
+ ncr_key_storage_unwrap);
+ CASE_NO_OUTPUT(NCRIO_SESSION_INIT, ncr_session_init, ncr_session_init);
+ CASE_NO_OUTPUT_COMPAT(NCRIO_SESSION_UPDATE, ncr_session_update,
+ ncr_session_update);
+ CASE_NO_OUTPUT_COMPAT(NCRIO_SESSION_FINAL, ncr_session_final,
+ ncr_session_final);
+ CASE_NO_OUTPUT_COMPAT(NCRIO_SESSION_ONCE, ncr_session_once,
+ ncr_session_once);
+ CASE_(NCRIO_MASTER_KEY_SET, ncr_master_key_set, ncr_master_key_set,
+ (&data, tb));
+ default:
+ return -EINVAL;
+#undef CASE_
+#undef CASE_NO_OUTPUT
+#undef CASE_NO_OUTPUT_COMPAT
+ }
+ kfree(attr_buf);
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_ncr_key_export {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ compat_uptr_t buffer;
+ compat_int_t buffer_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_EXPORT _IOWR('c', 209, struct compat_ncr_key_export)
+
+static void convert_ncr_key_export(struct ncr_key_export *new,
+ const struct compat_ncr_key_export *old)
+{
+ new->key = old->key;
+ new->buffer = compat_ptr(old->buffer);
+ new->buffer_size = old->buffer_size;
+}
+
+struct compat_ncr_key_import {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ compat_uptr_t data;
+ __u32 data_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_IMPORT _IOWR('c', 210, struct compat_ncr_key_import)
+
+static void convert_ncr_key_import(struct ncr_key_import *new,
+ const struct compat_ncr_key_import *old)
+{
+ new->key = old->key;
+ new->data = compat_ptr(old->data);
+ new->data_size = old->data_size;
+}
+
+struct compat_ncr_key_wrap {
+ __u32 input_size, output_size;
+ ncr_key_t wrapping_key;
+ ncr_key_t source_key;
+ compat_uptr_t buffer;
+ compat_int_t buffer_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_WRAP _IOWR('c', 250, struct compat_ncr_key_wrap)
+
+static void convert_ncr_key_wrap(struct ncr_key_wrap *new,
+ const struct compat_ncr_key_wrap *old)
+{
+ new->wrapping_key = old->wrapping_key;
+ new->source_key = old->source_key;
+ new->buffer = compat_ptr(old->buffer);
+ new->buffer_size = old->buffer_size;
+}
+
+struct compat_ncr_key_unwrap {
+ __u32 input_size, output_size;
+ ncr_key_t wrapping_key;
+ ncr_key_t dest_key;
+ compat_uptr_t data;
+ __u32 data_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_UNWRAP _IOWR('c', 251, struct compat_ncr_key_unwrap)
+
+static void convert_ncr_key_unwrap(struct ncr_key_unwrap *new,
+ const struct compat_ncr_key_unwrap *old)
+{
+ new->wrapping_key = old->wrapping_key;
+ new->dest_key = old->dest_key;
+ new->data = compat_ptr(old->data);
+ new->data_size = old->data_size;
+}
+
+struct compat_ncr_key_storage_wrap {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ compat_uptr_t buffer;
+ compat_int_t buffer_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_STORAGE_WRAP \
+ _IOWR('c', 261, struct compat_ncr_key_storage_wrap)
+
+static void convert_ncr_key_storage_wrap(struct ncr_key_storage_wrap *new,
+ const struct compat_ncr_key_storage_wrap *old)
+{
+ new->key = old->key;
+ new->buffer = compat_ptr(old->buffer);
+ new->buffer_size = old->buffer_size;
+}
+
+struct compat_ncr_key_storage_unwrap {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ compat_uptr_t data;
+ __u32 data_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_STORAGE_UNWRAP \
+ _IOWR('c', 262, struct compat_ncr_key_storage_wrap)
+
+static void convert_ncr_key_storage_unwrap(struct ncr_key_storage_unwrap *new,
+ const struct compat_ncr_key_storage_unwrap *old)
+{
+ new->key = old->key;
+ new->data = compat_ptr(old->data);
+ new->data_size = old->data_size;
+}
+
+struct compat_ncr_master_key_set {
+ __u32 input_size, output_size;
+ compat_uptr_t key;
+ __u32 key_size;
+ __NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_MASTER_KEY_SET \
+ _IOWR('c', 260, struct compat_ncr_master_key_set)
+
+static void convert_ncr_master_key_set(struct ncr_master_key_set *new,
+ const struct compat_ncr_master_key_set *old)
+{
+ new->key = compat_ptr(old->key);
+ new->key_size = old->key_size;
+}
+
+long
+ncr_compat_ioctl(struct ncr_lists *lst, unsigned int cmd, unsigned long arg_)
+{
+ void __user *arg = (void __user *)arg_;
+ struct nlattr *tb[NCR_ATTR_MAX + 1];
+ void *attr_buf;
+ int ret;
+
+ if (unlikely(!lst))
+ BUG();
+
+ switch (cmd) {
+ case NCRIO_KEY_INIT:
+ case NCRIO_KEY_GENERATE:
+ case NCRIO_KEY_GENERATE_PAIR:
+ case NCRIO_KEY_DERIVE:
+ case NCRIO_KEY_GET_INFO:
+ case NCRIO_KEY_DEINIT:
+ case NCRIO_SESSION_INIT:
+ return ncr_ioctl(lst, cmd, arg_);
+
+#define CASE_(LABEL, STRUCT, FUNCTION, ARGS) \
+ case (LABEL): { \
+ struct compat_##STRUCT old; \
+ struct STRUCT new; \
+ \
+ attr_buf = NCR_GET_INPUT_ARGS_NO_OUTPUT(&old, tb, arg); \
+ if (IS_ERR(attr_buf)) { \
+ err(); \
+ return PTR_ERR(attr_buf); \
+ } \
+ convert_##STRUCT(&new, &old); \
+ ret = (FUNCTION)ARGS; \
+ break; \
+ }
+#define CASE_NO_OUTPUT(LABEL, STRUCT, FUNCTION) \
+ CASE_(LABEL, STRUCT, FUNCTION, (lst, &new, tb))
+
+#define CASE_COMPAT_ONLY(LABEL, STRUCT, FUNCTION) \
+ case (LABEL): { \
+ struct STRUCT data; \
+ \
+ attr_buf = NCR_GET_INPUT_ARGS_NO_OUTPUT(&data, tb, arg); \
+ if (IS_ERR(attr_buf)) { \
+ err(); \
+ return PTR_ERR(attr_buf); \
+ } \
+ ret = (FUNCTION)(lst, &data, tb, 1); \
+ break; \
+ }
+
+ CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_EXPORT, ncr_key_export, ncr_key_export);
+ CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_IMPORT, ncr_key_import, ncr_key_import);
+ CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_WRAP, ncr_key_wrap, ncr_key_wrap);
+ CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_UNWRAP, ncr_key_unwrap, ncr_key_unwrap);
+ CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_STORAGE_WRAP, ncr_key_storage_wrap,
+ ncr_key_storage_wrap);
+ CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_STORAGE_UNWRAP, ncr_key_storage_unwrap,
+ ncr_key_storage_unwrap);
+ CASE_COMPAT_ONLY(NCRIO_SESSION_UPDATE, ncr_session_update,
+ ncr_session_update);
+ CASE_COMPAT_ONLY(NCRIO_SESSION_FINAL, ncr_session_final,
+ ncr_session_final);
+ CASE_COMPAT_ONLY(NCRIO_SESSION_ONCE, ncr_session_once,
+ ncr_session_once);
+ CASE_(COMPAT_NCRIO_MASTER_KEY_SET, ncr_master_key_set,
+ ncr_master_key_set, (&new, tb));
+ default:
+ return -EINVAL;
+#undef CASE_
+#undef CASE_NO_OUTPUT
+#undef CASE_COMPAT_ONLY
+ }
+ kfree(attr_buf);
+ return ret;
+}
+#endif
+
+int ncr_session_input_data_from_nla(struct ncr_session_input_data *dest,
+ const struct nlattr *nla, int compat)
+{
+ if (unlikely(nla == NULL))
+ return -EINVAL;
+#ifdef CONFIG_COMPAT
+ if (!compat) {
+#endif
+ if (unlikely(nla_len(nla) < sizeof(dest)))
+ return -ERANGE; /* nla_validate would return -ERANGE. */
+ memcpy(dest, nla_data(nla), sizeof(*dest));
+#ifdef CONFIG_COMPAT
+ } else {
+ struct compat_ncr_session_input_data old;
+
+ if (unlikely(nla_len(nla) < sizeof(old)))
+ return -ERANGE;
+ memcpy(&old, nla_data(nla), sizeof(old));
+ dest->data = compat_ptr(old.data);
+ dest->data_size = old.data_size;
+ }
+#endif
+ return 0;
+}
+
+int ncr_session_output_buffer_from_nla(struct ncr_session_output_buffer *dest,
+ const struct nlattr *nla, int compat)
+{
+ if (unlikely(nla == NULL))
+ return -EINVAL;
+#ifdef CONFIG_COMPAT
+ if (!compat) {
+#endif
+ if (unlikely(nla_len(nla) < sizeof(dest)))
+ return -ERANGE; /* nla_validate would return -ERANGE. */
+ memcpy(dest, nla_data(nla), sizeof(*dest));
+#ifdef CONFIG_COMPAT
+ } else {
+ struct compat_ncr_session_output_buffer old;
+
+ if (unlikely(nla_len(nla) < sizeof(old)))
+ return -ERANGE;
+ memcpy(&old, nla_data(nla), sizeof(old));
+ dest->buffer = compat_ptr(old.buffer);
+ dest->buffer_size = old.buffer_size;
+ dest->result_size_ptr = compat_ptr(old.result_size_ptr);
+ }
+#endif
+ return 0;
+}
+
+
+int ncr_session_output_buffer_set_size(const struct ncr_session_output_buffer *dest,
+ size_t size, int compat)
+{
+#ifdef CONFIG_COMPAT
+ if (!compat)
+#endif
+ return put_user(size, dest->result_size_ptr);
+#ifdef CONFIG_COMPAT
+ else {
+ compat_size_t old;
+
+ old = size;
+ return put_user(old,
+ (compat_size_t __user *)dest->result_size_ptr);
+ }
+#endif
+}
diff --git a/crypto/userspace/utils.c b/crypto/userspace/utils.c
new file mode 100644
index 00000000000..a427833fdad
--- /dev/null
+++ b/crypto/userspace/utils.c
@@ -0,0 +1,298 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2010 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * Red Hat Author: Miloslav Trmač
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <net/netlink.h>
+#include "ncr-int.h"
+#include "utils.h"
+
+#ifdef CONFIG_COMPAT
+/* max() is too clever for compile-time constants */
+#define CONST_MAX(A, B) ((A) > (B) ? (A) : (B))
+
+#define MAX_SESSION_INPUT_DATA_SIZE \
+ (CONST_MAX(sizeof(struct ncr_session_input_data), \
+ sizeof(struct compat_ncr_session_input_data)))
+#define MAX_SESSION_OUTPUT_BUFFER_SIZE \
+ (CONST_MAX(sizeof(struct ncr_session_output_buffer), \
+ sizeof(struct compat_ncr_session_output_buffer)))
+
+#else /* !CONFIG_COMPAT */
+
+#define MAX_SESSION_INPUT_DATA_SIZE (sizeof(struct ncr_session_input_data))
+#define MAX_SESSION_OUTPUT_BUFFER_SIZE \
+ (sizeof(struct ncr_session_output_buffer))
+
+#endif /* !CONFIG_COMPAT */
+
+static const struct nla_policy ncr_attr_policy[NCR_ATTR_MAX + 1] = {
+ [NCR_ATTR_ALGORITHM] = { NLA_NUL_STRING, 0 },
+ [NCR_ATTR_DERIVATION_ALGORITHM] = { NLA_NUL_STRING, 0 },
+ [NCR_ATTR_SIGNATURE_HASH_ALGORITHM] = { NLA_NUL_STRING, 0 },
+ [NCR_ATTR_WRAPPING_ALGORITHM] = { NLA_NUL_STRING, 0 },
+ [NCR_ATTR_UPDATE_INPUT_DATA] = {
+ NLA_BINARY, MAX_SESSION_INPUT_DATA_SIZE
+ },
+ [NCR_ATTR_UPDATE_OUTPUT_BUFFER] = {
+ NLA_BINARY, MAX_SESSION_OUTPUT_BUFFER_SIZE
+ },
+ [NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA] = { NLA_U32, 0 },
+ [NCR_ATTR_FINAL_INPUT_DATA] = {
+ NLA_BINARY, MAX_SESSION_INPUT_DATA_SIZE
+ },
+ [NCR_ATTR_FINAL_OUTPUT_BUFFER] = {
+ NLA_BINARY, MAX_SESSION_OUTPUT_BUFFER_SIZE
+ },
+ [NCR_ATTR_KEY] = { NLA_U32, 0 },
+ [NCR_ATTR_KEY_FLAGS] = { NLA_U32, 0 },
+ [NCR_ATTR_KEY_ID] = { NLA_BINARY, 0 },
+ [NCR_ATTR_KEY_TYPE] = { NLA_U32, 0 },
+ [NCR_ATTR_IV] = { NLA_BINARY, 0 },
+ [NCR_ATTR_SECRET_KEY_BITS] = { NLA_U32, 0 },
+ [NCR_ATTR_RSA_MODULUS_BITS] = { NLA_U32, 0 },
+ [NCR_ATTR_RSA_E] = { NLA_BINARY, 0 },
+ [NCR_ATTR_RSA_ENCODING_METHOD] = { NLA_U32, 0 },
+ [NCR_ATTR_RSA_OAEP_HASH_ALGORITHM] = { NLA_NUL_STRING, 0 },
+ [NCR_ATTR_RSA_PSS_SALT_LENGTH] = { NLA_U32, 0 },
+ [NCR_ATTR_DSA_P_BITS] = { NLA_U32, 0 },
+ [NCR_ATTR_DSA_Q_BITS] = { NLA_U32, 0 },
+ [NCR_ATTR_DH_PRIME] = { NLA_BINARY, 0 },
+ [NCR_ATTR_DH_BASE] = { NLA_BINARY, 0 },
+ [NCR_ATTR_DH_PUBLIC] = { NLA_BINARY, 0 },
+ [NCR_ATTR_WANTED_ATTRS] = { NLA_BINARY, 0 },
+ [NCR_ATTR_SESSION_CLONE_FROM] = { NLA_U32, 0 },
+};
+
+void *__ncr_get_input_args(void *fixed, struct nlattr *tb[], size_t fixed_size,
+ u32 *input_size_ptr, const void __user *arg)
+{
+ size_t input_size, buf_size;
+ void *buf;
+ int ret;
+
+ if (unlikely(copy_from_user(fixed, arg, fixed_size))) {
+ err();
+ return ERR_PTR(-EFAULT);
+ }
+ input_size = *input_size_ptr;
+
+ /* NCR_GET_INPUT_ARGS/NCR_GET_INPUT_ARGS_NO_OUTPUT has verified
+ fixed_size is correctly aligned for a struct nlattr. */
+ if (input_size == 0)
+ input_size = fixed_size;
+ else if (unlikely(input_size < fixed_size)) {
+ err();
+ return ERR_PTR(-EINVAL);
+ }
+ buf_size = input_size - fixed_size;
+ if (unlikely(buf_size > NCR_MAX_ATTR_SIZE)) {
+ err();
+ return ERR_PTR(-EOVERFLOW);
+ }
+
+ if (buf_size == 0)
+ buf = NULL;
+ else {
+ const char __user *var_arg;
+
+ buf = kmalloc(buf_size, GFP_KERNEL);
+ if (unlikely(buf == NULL)) {
+ err();
+ return ERR_PTR(-ENOMEM);
+ }
+ var_arg = (const char __user *)arg + fixed_size;
+ if (unlikely(copy_from_user(buf, var_arg, buf_size))) {
+ err();
+ ret = -EFAULT;
+ goto err_buf;
+ }
+ }
+
+ ret = nla_parse(tb, NCR_ATTR_MAX, buf, buf_size, ncr_attr_policy);
+ if (ret != 0) {
+ err();
+ goto err_buf;
+ }
+
+ return buf;
+
+err_buf:
+ kfree(buf);
+ return ERR_PTR(ret);
+}
+
+static int update_output_size(void __user *arg, size_t output_size_offset,
+ u32 old_value, u32 new_value)
+{
+ if (old_value != 0 && old_value != new_value) {
+ u32 __user *dest;
+
+ dest = (u32 __user *)((char __user *)arg + output_size_offset);
+ return put_user(new_value, dest);
+ }
+ return 0;
+}
+
+void *__ncr_get_input_args_no_output(void *fixed, struct nlattr *tb[],
+ size_t fixed_size, u32 *input_size_ptr,
+ size_t output_size_offset,
+ void __user *arg)
+{
+ void *attr_buf;
+ u32 output_size;
+ int ret;
+
+ attr_buf = __ncr_get_input_args(fixed, tb, fixed_size, input_size_ptr,
+ arg);
+ if (IS_ERR(attr_buf))
+ return attr_buf;
+
+ output_size = *(const u32 *)((const char *)fixed + output_size_offset);
+ ret = update_output_size(arg, output_size_offset, output_size,
+ fixed_size);
+ if (ret != 0) {
+ kfree(attr_buf);
+ return ERR_PTR(ret);
+ }
+ return attr_buf;
+}
+
+int __ncr_out_init(struct ncr_out *out, const void *fixed, size_t fixed_size,
+ size_t output_size_offset, void __user *arg)
+{
+ u32 output_size;
+
+ /* NCR_OUT_INIT has verified fixed_size is correctly aligned for a
+ struct nlattr. */
+ output_size = *(const u32 *)((const char *)fixed + output_size_offset);
+ if (output_size == 0)
+ out->left = 0;
+ else {
+ /* NCR_OUT_INIT has verified fixed_size is correctly aligned for
+ a struct nlattr. */
+ if (output_size < fixed_size)
+ return -EINVAL;
+ out->left = min_t(size_t, output_size - fixed_size,
+ NCR_MAX_ATTR_SIZE);
+ }
+ out->buf = kmalloc(out->left, GFP_KERNEL);
+ if (out->buf == NULL)
+ return -ENOMEM;
+ out->p = out->buf;
+ out->arg = arg;
+ out->output_size_offset = output_size_offset;
+ out->fixed_size = fixed_size;
+ out->orig_output_size = output_size;
+ return 0;
+}
+
+int ncr_out_finish(struct ncr_out *out)
+{
+ size_t buf_size;
+
+ buf_size = (char *)out->p - (char *)out->buf;
+ if (buf_size != 0) {
+ if (unlikely(copy_to_user((char __user *)out->arg
+ + out->fixed_size,
+ out->buf, buf_size)))
+ return -EFAULT;
+ }
+
+ return update_output_size(out->arg, out->output_size_offset,
+ out->orig_output_size,
+ out->fixed_size + buf_size);
+}
+
+void ncr_out_free(struct ncr_out *out)
+{
+ kfree(out->buf);
+}
+
+struct nlattr *ncr_out_reserve(struct ncr_out *out, int attrtype, int attrlen)
+{
+ size_t needed;
+ struct nlattr *nla;
+
+ needed = nla_total_size(attrlen);
+ if (out->left < needed)
+ ERR_PTR(-ERANGE);
+ nla = out->p;
+ out->p = (char *)out->p + needed;
+ out->left -= needed;
+
+ nla->nla_len = nla_attr_size(attrlen);
+ nla->nla_type = attrtype;
+ memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(attrlen));
+ return nla;
+}
+
+int ncr_out_put(struct ncr_out *out, int attrtype, int attrlen, const void *data)
+{
+ struct nlattr *nla;
+
+ nla = ncr_out_reserve(out, attrtype, attrlen);
+ if (IS_ERR(nla))
+ return PTR_ERR(nla);
+ memcpy(nla_data(nla), data, attrlen);
+ return 0;
+}
+
+/**
+ * Initialize a nlattr with @attrtype as a buffer of maximum possible size in
+ * @out. The buffer must be finalized using ncr_out_commit_buffer.
+ */
+struct nlattr *ncr_out_begin_buffer(struct ncr_out *out, int attrtype)
+{
+ struct nlattr *nla;
+
+ if (out->left < NLA_HDRLEN)
+ return ERR_PTR(-ERANGE);
+ nla = out->p;
+
+ /* Ensure the rounding down of out->left does not decrease it below
+ NLA_HDRLEN. */
+ BUILD_BUG_ON(NLA_ALIGN(NLA_HDRLEN) != NLA_HDRLEN);
+ nla->nla_len = out->left & ~(NLA_ALIGNTO - 1);
+ nla->nla_type = attrtype;
+ return nla;
+}
+
+/**
+ * Set the length of buffer initialied in @out with ncr_out_begin_buffer() to
+ * @attrlen and allow adding more attributes.
+ */
+void ncr_out_commit_buffer(struct ncr_out *out, int attrlen)
+{
+ struct nlattr *nla;
+ size_t total;
+
+ nla = out->p;
+ nla->nla_len = nla_attr_size(attrlen);
+ memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(attrlen));
+ total = nla_total_size(attrlen);
+
+ out->p = (char *)out->p + total;
+ out->left -= total;
+}
diff --git a/crypto/userspace/utils.h b/crypto/userspace/utils.h
new file mode 100644
index 00000000000..2802afa7758
--- /dev/null
+++ b/crypto/userspace/utils.h
@@ -0,0 +1,98 @@
+#ifndef NCR_UTILS_H
+#define NCR_UTILS_H
+
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+
+#define NCR_MAX_ATTR_SIZE 4096
+
+struct nlattr;
+
+struct ncr_out {
+ void *buf, *p;
+ size_t left;
+ void __user *arg;
+ size_t output_size_offset, fixed_size;
+ u32 orig_output_size;
+};
+
+#define __NCR_VERIFY_FIXED_SIZE(fixed) \
+ (BUILD_BUG_ON(sizeof(*(fixed)) != NLA_ALIGN(sizeof(*(fixed)))))
+#define __NCR_VERIFY_TB(tb) (BUILD_BUG_ON(ARRAY_SIZE(tb) != NCR_ATTR_MAX + 1))
+
+extern u32 __ncr_u32_type_check;
+#define __OUT_SIZE_OFF(fixed) \
+ ((void)(&(fixed)->output_size == &__ncr_u32_type_check), \
+ (char *)&(fixed)->output_size - (char *)(fixed))
+
+
+/**
+ * Load *@fixed and a sequence of netlink-like attributes from @arg. @fixed
+ * contains "input_size", which is an u32 filled with total input size,
+ * including the attributes, which are parsed into @tb.
+ */
+#define NCR_GET_INPUT_ARGS(fixed, tb, arg) \
+ (__NCR_VERIFY_FIXED_SIZE(fixed), \
+ __NCR_VERIFY_TB(tb), \
+ __ncr_get_input_args(fixed, tb, sizeof(*(fixed)), \
+ &(fixed)->input_size, arg))
+void *__ncr_get_input_args(void *fixed, struct nlattr *tb[], size_t fixed_size,
+ u32 *input_size_ptr, const void __user *arg);
+
+/**
+ * Load *@fixed and a sequence of netlink-like attributes from @arg. @fixed
+ * contains "input_size", which is an u32 filled with total input size,
+ * including the attributes, which are parsed into @tb. In addition, indicate
+ * to the user through u32 "output_size" that no output attributes will be
+ * returned.
+ */
+#define NCR_GET_INPUT_ARGS_NO_OUTPUT(fixed, tb, arg) \
+ (__NCR_VERIFY_FIXED_SIZE(fixed), \
+ __NCR_VERIFY_TB(tb), \
+ __ncr_get_input_args_no_output(fixed, tb, sizeof(*(fixed)), \
+ &(fixed)->input_size, \
+ __OUT_SIZE_OFF(fixed), arg))
+void *__ncr_get_input_args_no_output(void *fixed, struct nlattr *tb[],
+ size_t fixed_size, u32 *input_size_ptr,
+ size_t output_size_offset,
+ void __user *arg);
+
+/**
+ * Return a new output attribute context for attributes of *@fixed. @fixed
+ * contains "output_size", an u32 containing total output size, including
+ * @fixed. Store @arg for later ncr_out_finish().
+ */
+#define NCR_OUT_INIT(out, fixed, arg) \
+ (__NCR_VERIFY_FIXED_SIZE(fixed), \
+ __ncr_out_init((out), (fixed), sizeof(*(fixed)), \
+ __OUT_SIZE_OFF(fixed), (arg)))
+int __ncr_out_init(struct ncr_out *out, const void *fixed, size_t fixed_size,
+ size_t output_size_offset, void __user *arg);
+
+/**
+ * Write attributes from @out to user space and update user-space output_size.
+ */
+int ncr_out_finish(struct ncr_out *out);
+
+void ncr_out_free(struct ncr_out *out);
+
+int ncr_out_put(struct ncr_out *out, int attrtype, int attrlen,
+ const void *data);
+
+static inline int ncr_out_put_u32(struct ncr_out *out, int attrtype, u32 value)
+{
+ return ncr_out_put(out, attrtype, sizeof(value), &value);
+}
+
+static inline int ncr_out_put_string(struct ncr_out *out, int attrtype,
+ const char *value)
+{
+ return ncr_out_put(out, attrtype, strlen(value) + 1, value);
+}
+
+struct nlattr *ncr_out_reserve(struct ncr_out *out, int attrtype, int attrlen);
+
+struct nlattr *ncr_out_begin_buffer(struct ncr_out *out, int attrtype);
+void ncr_out_commit_buffer(struct ncr_out *out, int attrlen);
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 756f831cbdd..41790cd58dd 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -116,6 +116,7 @@ header-y += mmtimer.h
header-y += mqueue.h
header-y += mtio.h
header-y += ncp_no.h
+header-y += ncr.h
header-y += neighbour.h
header-y += net_dropmon.h
header-y += net_tstamp.h
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 3c7a358241a..cfb33639566 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -122,6 +122,11 @@
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
+#define AUDIT_CRYPTO_STORAGE_KEY 1600 /* Key storage key configured */
+#define AUDIT_CRYPTO_USERSPACE_OP 1601 /* User-space crypto operation */
+#define AUDIT_CRYPTO_KEY_VALUE 1602 /* Public values of a key, immediatelly
+ follows USERSPACE_OP. */
+
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
@@ -207,6 +212,7 @@
#define AUDIT_OBJ_TYPE 21
#define AUDIT_OBJ_LEV_LOW 22
#define AUDIT_OBJ_LEV_HIGH 23
+#define AUDIT_CRYPTO_OP 24
/* These are ONLY useful when checking
* at syscall exit time (AUDIT_AT_EXIT). */
@@ -314,6 +320,20 @@ enum {
#define AUDIT_PERM_READ 4
#define AUDIT_PERM_ATTR 8
+#define AUDIT_CRYPTO_OP_CONTEXT_NEW 1
+#define AUDIT_CRYPTO_OP_CONTEXT_DEL 2
+#define AUDIT_CRYPTO_OP_SESSION_INIT 3
+#define AUDIT_CRYPTO_OP_SESSION_OP 4
+#define AUDIT_CRYPTO_OP_SESSION_FINAL 5
+#define AUDIT_CRYPTO_OP_KEY_IMPORT 6
+#define AUDIT_CRYPTO_OP_KEY_EXPORT 7
+#define AUDIT_CRYPTO_OP_KEY_WRAP 8
+#define AUDIT_CRYPTO_OP_KEY_UNWRAP 9
+#define AUDIT_CRYPTO_OP_KEY_GEN 10
+#define AUDIT_CRYPTO_OP_KEY_DERIVE 11
+#define AUDIT_CRYPTO_OP_KEY_ZEROIZE 12
+#define AUDIT_CRYPTO_OP_KEY_GET_INFO 13
+
struct audit_status {
__u32 mask; /* Bit mask for valid entries */
__u32 enabled; /* 1 = enabled, 0 = disabled */
@@ -404,6 +424,12 @@ struct audit_field {
void *lsm_rule;
};
+struct audit_crypto_value {
+ char name;
+ void *value;
+ size_t value_size;
+};
+
#define AUDITSC_INVALID 0
#define AUDITSC_SUCCESS 1
#define AUDITSC_FAILURE 2
@@ -479,6 +505,12 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
const struct cred *new,
const struct cred *old);
extern void __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old);
+extern int __audit_log_crypto_op(int op, int context, int session,
+ const char *operation, const char *algorithm,
+ int key1, void *key1_id, size_t key1_id_size,
+ int key2, void *key2_id, size_t key2_id_size);
+extern void __audit_log_crypto_values(const struct audit_crypto_value *values,
+ size_t num_values);
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
@@ -532,6 +564,27 @@ static inline void audit_log_capset(pid_t pid, const struct cred *new,
__audit_log_capset(pid, new, old);
}
+static inline int audit_log_crypto_op(int op, int context, int session,
+ const char *operation,
+ const char *algorithm, int key1,
+ void *key1_id, size_t key1_id_size,
+ int key2, void *key2_id,
+ size_t key2_id_size)
+{
+ if (likely(audit_dummy_context()))
+ return 0;
+ return __audit_log_crypto_op(op, context, session, operation, algorithm,
+ key1, key1_id, key1_id_size, key2, key2_id,
+ key2_id_size);
+}
+
+static inline void audit_log_crypto_values(const struct audit_crypto_value *a,
+ size_t num_values)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_log_crypto_values(a, num_values);
+}
+
extern int audit_n_rules;
extern int audit_signals;
#else
@@ -565,6 +618,8 @@ extern int audit_signals;
#define audit_mq_getsetattr(d,s) ((void)0)
#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; })
#define audit_log_capset(pid, ncr, ocr) ((void)0)
+#define audit_log_crypto_op(op, ctx, sess, k1, id1, size1, k2, id2, size2) (0)
+#define audit_log_crypto_values(a, values, num_values) ((void)0)
#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
#define audit_signals 0
diff --git a/include/linux/ncr.h b/include/linux/ncr.h
new file mode 100644
index 00000000000..cd18d4b6a9a
--- /dev/null
+++ b/include/linux/ncr.h
@@ -0,0 +1,287 @@
+#ifndef _LINUX_NCR_H
+#define _LINUX_NCR_H
+
+#include <linux/types.h>
+
+/* Serves to make sure the structure is suitably aligned to continue with
+ a struct nlattr without external padding.
+
+ 4 is NLA_ALIGNTO from <linux/netlink.h>, but if we
+ included <linux/netlink.h>, the user would have to include <sys/socket.h>
+ as well for no obvious reason. "4" is fixed by ABI. */
+#define __NL_ATTRIBUTES char __align[] __attribute__((aligned(4)))
+
+/* In all ioctls, input_size specifies size of the ncr_* structure and the
+ following attributes.
+
+ output_size specifies space available for returning output, including the
+ initial ncr_* structure, and is updated by the ioctl() with the space
+ actually used.
+
+ There are two special cases: input_size 0 means not attributes are supplied,
+ and is treated equivalent to sizeof(struct ncr_*). output_size 0 means no
+ space for output attributes is available, and is not updated. */
+
+/* FIXME: better names for algorithm parameters? */
+/* FIXME: Split key generation/derivation attributes to decrease the number
+ of attributes used for the frequent operations? */
+enum {
+ NCR_ATTR_UNSPEC, /* 0 is special in lib/nlattr.c. */
+ NCR_ATTR_ALGORITHM, /* NLA_NUL_STRING */
+ NCR_ATTR_DERIVATION_ALGORITHM, /* NLA_NUL_STRING - NCR_DERIVE_* */
+ NCR_ATTR_SIGNATURE_HASH_ALGORITHM, /* NLA_NUL_STRING */
+ NCR_ATTR_WRAPPING_ALGORITHM, /* NLA_NUL_STRING - NCR_WALG_* */
+ NCR_ATTR_UPDATE_INPUT_DATA, /* NLA_BINARY - ncr_session_input_data */
+ /* NLA_BINARY - ncr_session_output_buffer */
+ NCR_ATTR_UPDATE_OUTPUT_BUFFER,
+ NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA, /* NLA_U32 - ncr_key_t */
+ NCR_ATTR_FINAL_INPUT_DATA, /* NLA_BINARY - ncr_session_input_data */
+ /* NLA_BINARY - ncr_session_output_buffer */
+ NCR_ATTR_FINAL_OUTPUT_BUFFER,
+ NCR_ATTR_KEY, /* NLA_U32 - ncr_key_t */
+ NCR_ATTR_KEY_FLAGS, /* NLA_U32 - NCR_KEY_FLAG_* */
+ NCR_ATTR_KEY_ID, /* NLA_BINARY */
+ NCR_ATTR_KEY_TYPE, /* NLA_U32 - ncr_key_type_t */
+ NCR_ATTR_IV, /* NLA_BINARY */
+ NCR_ATTR_SECRET_KEY_BITS, /* NLA_U32 */
+ NCR_ATTR_RSA_MODULUS_BITS, /* NLA_U32 */
+ NCR_ATTR_RSA_E, /* NLA_BINARY */
+ NCR_ATTR_RSA_ENCODING_METHOD, /* NLA_U32 - ncr_rsa_type_t */
+ NCR_ATTR_RSA_OAEP_HASH_ALGORITHM, /* NLA_NUL_STRING */
+ NCR_ATTR_RSA_PSS_SALT_LENGTH, /* NLA_U32 */
+ NCR_ATTR_DSA_P_BITS, /* NLA_U32 */
+ NCR_ATTR_DSA_Q_BITS, /* NLA_U32 */
+ NCR_ATTR_DH_PRIME, /* NLA_BINARY */
+ NCR_ATTR_DH_BASE, /* NLA_BINARY */
+ NCR_ATTR_DH_PUBLIC, /* NLA_BINARY */
+ NCR_ATTR_WANTED_ATTRS, /* NLA_BINARY - array of u16 IDs */
+ NCR_ATTR_SESSION_CLONE_FROM, /* NLA_U32 - ncr_session_t */
+
+ /* Add new attributes here */
+
+ NCR_ATTR_END__,
+ NCR_ATTR_MAX = NCR_ATTR_END__ - 1
+};
+
+#define NCR_CIPHER_MAX_BLOCK_LEN 32
+#define NCR_HASH_MAX_OUTPUT_SIZE 64
+
+/* Better names wanted */
+#define NCR_ALG_DSA_TRANSPARENT_HASH "__dsa_transparent_hash"
+#define NCR_ALG_RSA_TRANSPARENT_HASH "__rsa_transparent_hash"
+
+#define NCR_WALG_AES_RFC3394 "walg-aes-rfc3394" /* for secret keys only */
+#define NCR_WALG_AES_RFC5649 "walg-aes-rfc5649" /* can wrap arbitrary key */
+
+typedef enum {
+ NCR_KEY_TYPE_INVALID,
+ NCR_KEY_TYPE_SECRET=1,
+ NCR_KEY_TYPE_PUBLIC=2,
+ NCR_KEY_TYPE_PRIVATE=3,
+} ncr_key_type_t;
+
+/* Key handling
+ */
+
+typedef __s32 ncr_key_t;
+
+#define NCR_KEY_INVALID ((ncr_key_t)-1)
+
+#define NCR_KEY_FLAG_EXPORTABLE 1
+#define NCR_KEY_FLAG_WRAPPABLE (1<<1)
+/* when generating a pair the flags correspond to private
+ * and public key usage is implicit. For example when private
+ * key can decrypt then public key can encrypt. If private key
+ * can sign then public key can verify.
+ */
+#define NCR_KEY_FLAG_DECRYPT (1<<2)
+#define NCR_KEY_FLAG_SIGN (1<<3)
+#define NCR_KEY_FLAG_ENCRYPT (1<<4)
+#define NCR_KEY_FLAG_VERIFY (1<<5)
+/* These flags can only be set by administrator, to prevent
+ * adversaries exporting wrappable keys with random ones.
+ */
+#define NCR_KEY_FLAG_WRAPPING (1<<6)
+#define NCR_KEY_FLAG_UNWRAPPING (1<<7)
+#define NCR_KEY_FLAG_HASHABLE (1<<8)
+#define NCR_KEY_FLAG_ALLOW_TRANSPARENT_HASH (1<<9)
+
+struct ncr_key_generate {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_key_generate_pair {
+ __u32 input_size, output_size;
+ ncr_key_t private_key;
+ ncr_key_t public_key;
+ __NL_ATTRIBUTES;
+};
+
+typedef enum {
+ RSA_PKCS1_V1_5, /* both signatures and encryption */
+ RSA_PKCS1_OAEP, /* for encryption only */
+ RSA_PKCS1_PSS, /* for signatures only */
+} ncr_rsa_type_t;
+
+#define NCR_DERIVE_DH "dh"
+
+
+struct ncr_key_derive {
+ __u32 input_size, output_size;
+ ncr_key_t input_key;
+ ncr_key_t new_key;
+ __NL_ATTRIBUTES;
+};
+
+#define MAX_KEY_ID_SIZE 20
+
+struct ncr_key_get_info {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_key_import {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ const void __user *data;
+ __u32 data_size;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_key_export {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ void __user *buffer;
+ int buffer_size;
+ __NL_ATTRIBUTES;
+};
+
+#define NCRIO_KEY_INIT _IO('c', 0xC0)
+/* generate a secret key */
+#define NCRIO_KEY_GENERATE _IOWR('c', 0xC1, struct ncr_key_generate)
+/* generate a public key pair */
+#define NCRIO_KEY_GENERATE_PAIR _IOWR('c', 0xC2, struct ncr_key_generate_pair)
+/* derive a new key from an old one */
+#define NCRIO_KEY_DERIVE _IOWR('c', 0xC3, struct ncr_key_derive)
+/* return information on a key */
+#define NCRIO_KEY_GET_INFO _IOWR('c', 0xC4, struct ncr_key_get_info)
+/* export a secret key */
+#define NCRIO_KEY_EXPORT _IOWR('c', 0xC5, struct ncr_key_export)
+/* import a secret key */
+#define NCRIO_KEY_IMPORT _IOWR('c', 0xC6, struct ncr_key_import)
+
+#define NCRIO_KEY_DEINIT _IOW('c', 0xC7, ncr_key_t)
+
+/* Key wrap ioctls
+ */
+struct ncr_key_wrap {
+ __u32 input_size, output_size;
+ ncr_key_t wrapping_key;
+ ncr_key_t source_key;
+ void __user *buffer;
+ int buffer_size;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_key_unwrap {
+ __u32 input_size, output_size;
+ ncr_key_t wrapping_key;
+ ncr_key_t dest_key;
+ const void __user *data;
+ __u32 data_size;
+ __NL_ATTRIBUTES;
+};
+
+#define NCRIO_KEY_WRAP _IOWR('c', 0xC8, struct ncr_key_wrap)
+#define NCRIO_KEY_UNWRAP _IOWR('c', 0xC9, struct ncr_key_unwrap)
+
+/* Internal ops */
+struct ncr_master_key_set {
+ __u32 input_size, output_size;
+ const void __user *key;
+ __u32 key_size;
+ __NL_ATTRIBUTES;
+};
+
+#define NCRIO_MASTER_KEY_SET _IOWR('c', 0xCA, struct ncr_master_key_set)
+
+/* These are similar to key_wrap and unwrap except that will store some extra
+ * fields to be able to recover a key */
+struct ncr_key_storage_wrap {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ void __user *buffer;
+ int buffer_size;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_key_storage_unwrap {
+ __u32 input_size, output_size;
+ ncr_key_t key;
+ const void __user *data;
+ __u32 data_size;
+ __NL_ATTRIBUTES;
+};
+
+#define NCRIO_KEY_STORAGE_WRAP _IOWR('c', 0xCB, struct ncr_key_storage_wrap)
+#define NCRIO_KEY_STORAGE_UNWRAP _IOWR('c', 0xCC, struct ncr_key_storage_wrap)
+
+/* Crypto Operations ioctls
+ */
+
+typedef enum {
+ NCR_OP_ENCRYPT=1,
+ NCR_OP_DECRYPT,
+ NCR_OP_SIGN,
+ NCR_OP_VERIFY,
+} ncr_crypto_op_t;
+
+typedef __s32 ncr_session_t;
+#define NCR_SESSION_INVALID ((ncr_session_t)-1)
+
+struct ncr_session_input_data {
+ const void __user *data;
+ __kernel_size_t data_size;
+};
+
+struct ncr_session_output_buffer {
+ void __user *buffer;
+ __kernel_size_t buffer_size;
+ __kernel_size_t __user *result_size_ptr;
+};
+
+struct ncr_session_init {
+ __u32 input_size, output_size;
+ __u32 op; /* ncr_crypto_op_t */
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_session_update {
+ __u32 input_size, output_size;
+ ncr_session_t ses;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_session_final {
+ __u32 input_size, output_size;
+ ncr_session_t ses;
+ __NL_ATTRIBUTES;
+};
+
+struct ncr_session_once {
+ __u32 input_size, output_size;
+ ncr_crypto_op_t op;
+ __NL_ATTRIBUTES;
+};
+
+#define NCRIO_SESSION_INIT _IOWR('c', 0xD0, struct ncr_session_init)
+#define NCRIO_SESSION_UPDATE _IOWR('c', 0xD1, struct ncr_session_update)
+#define NCRIO_SESSION_FINAL _IOWR('c', 0xD2, struct ncr_session_final)
+
+/* everything in one call */
+#define NCRIO_SESSION_ONCE _IOWR('c', 0xD3, struct ncr_session_once)
+
+#endif
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a70604047f3..a25a587dc87 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -363,6 +363,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
case AUDIT_DEVMINOR:
case AUDIT_EXIT:
case AUDIT_SUCCESS:
+ case AUDIT_CRYPTO_OP:
/* bit ops are only useful on syscall args */
if (f->op == Audit_bitmask || f->op == Audit_bittest)
goto exit_free;
@@ -457,6 +458,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
case AUDIT_ARG1:
case AUDIT_ARG2:
case AUDIT_ARG3:
+ case AUDIT_CRYPTO_OP:
break;
case AUDIT_ARCH:
entry->rule.arch_f = f;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index fc0f928167e..30853986ab9 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -50,6 +50,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mount.h>
+#include <linux/ncr.h>
#include <linux/socket.h>
#include <linux/mqueue.h>
#include <linux/audit.h>
@@ -80,6 +81,9 @@
/* no execve audit message should be longer than this (userspace limits) */
#define MAX_EXECVE_AUDIT_LEN 7500
+/* Number of public key values that can be audited */
+#define AUDIT_MAX_CRYPTO_KEY_VALUES 4
+
/* number of audit rules */
int audit_n_rules;
@@ -157,6 +161,32 @@ struct audit_aux_data_capset {
struct audit_cap_data cap;
};
+#define AUDIT_CRYPTO_OP_KEY_VALUE -1
+struct audit_crypto_header {
+ struct list_head list;
+ int op; /* AUDIT_CRYPTO_OP_KEY_VALUE for key values */
+};
+
+struct audit_crypto_op {
+ struct audit_crypto_header hdr;
+ int context;
+ int session;
+ const char *operation;
+ const char *algorithm;
+ int key1;
+ unsigned char key1_id[MAX_KEY_ID_SIZE];
+ size_t key1_id_size;
+ int key2;
+ unsigned char key2_id[MAX_KEY_ID_SIZE];
+ size_t key2_id_size;
+};
+
+struct audit_crypto_values {
+ struct audit_crypto_header hdr;
+ size_t num_values;
+ struct audit_crypto_value values[AUDIT_MAX_CRYPTO_KEY_VALUES];
+};
+
struct audit_tree_refs {
struct audit_tree_refs *next;
struct audit_chunk *c[31];
@@ -181,6 +211,7 @@ struct audit_context {
struct audit_context *previous; /* For nested syscalls */
struct audit_aux_data *aux;
struct audit_aux_data *aux_pids;
+ struct list_head crypto;
struct sockaddr_storage *sockaddr;
size_t sockaddr_len;
/* Save things to print about task_struct */
@@ -632,6 +663,21 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_FILETYPE:
result = audit_match_filetype(ctx, f->val);
break;
+ case AUDIT_CRYPTO_OP: {
+ struct audit_crypto_header *ax;
+
+ if (!ctx)
+ break;
+ list_for_each_entry(ax, &ctx->crypto, list) {
+ if (ax->op == AUDIT_CRYPTO_OP_KEY_VALUE)
+ continue;
+ result = audit_comparator(ax->op, f->op,
+ f->val);
+ if (result)
+ break;
+ }
+ break;
+ }
}
if (!result) {
@@ -824,9 +870,23 @@ static inline void audit_free_names(struct audit_context *context)
context->pwd.mnt = NULL;
}
+static void audit_free_crypto_op(struct audit_crypto_header *crypto)
+{
+ if (crypto->op == AUDIT_CRYPTO_OP_KEY_VALUE) {
+ struct audit_crypto_values *val;
+ size_t i;
+
+ val = (struct audit_crypto_values *)crypto;
+ for (i = 0; i < val->num_values; i++)
+ kfree(val->values[i].value);
+ }
+ kfree(crypto);
+}
+
static inline void audit_free_aux(struct audit_context *context)
{
struct audit_aux_data *aux;
+ struct audit_crypto_header *crypto, *tmp;
while ((aux = context->aux)) {
context->aux = aux->next;
@@ -836,6 +896,10 @@ static inline void audit_free_aux(struct audit_context *context)
context->aux_pids = aux->next;
kfree(aux);
}
+ list_for_each_entry_safe(crypto, tmp, &context->crypto, list) {
+ list_del(&crypto->list);
+ audit_free_crypto_op(crypto);
+ }
}
static inline void audit_zero_context(struct audit_context *context,
@@ -853,6 +917,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
if (!(context = kmalloc(sizeof(*context), GFP_KERNEL)))
return NULL;
audit_zero_context(context, state);
+ INIT_LIST_HEAD(&context->crypto);
INIT_LIST_HEAD(&context->killed_trees);
return context;
}
@@ -1310,12 +1375,91 @@ static void show_special(struct audit_context *context, int *call_panic)
audit_log_end(ab);
}
+static void log_crypto_op(struct audit_context *context,
+ const struct audit_crypto_header *header)
+{
+ static const char *const ops[] = {
+ [AUDIT_CRYPTO_OP_CONTEXT_NEW] = "context_new",
+ [AUDIT_CRYPTO_OP_CONTEXT_DEL] = "context_del",
+ [AUDIT_CRYPTO_OP_SESSION_INIT] = "session_init",
+ [AUDIT_CRYPTO_OP_SESSION_OP] = "session_op",
+ [AUDIT_CRYPTO_OP_SESSION_FINAL] = "session_final",
+ [AUDIT_CRYPTO_OP_KEY_IMPORT] = "key_import",
+ [AUDIT_CRYPTO_OP_KEY_EXPORT] = "key_export",
+ [AUDIT_CRYPTO_OP_KEY_WRAP] = "key_wrap",
+ [AUDIT_CRYPTO_OP_KEY_UNWRAP] = "key_unwrap",
+ [AUDIT_CRYPTO_OP_KEY_GEN] = "key_gen",
+ [AUDIT_CRYPTO_OP_KEY_DERIVE] = "key_derive",
+ [AUDIT_CRYPTO_OP_KEY_ZEROIZE] = "key_zeroize",
+ [AUDIT_CRYPTO_OP_KEY_GET_INFO] = "key_get_info",
+ };
+
+ const struct audit_crypto_op *crypto;
+ struct audit_buffer *ab;
+
+ crypto = (struct audit_crypto_op *)header;
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_CRYPTO_USERSPACE_OP);
+ if (!ab)
+ return;
+ if (header->op < ARRAY_SIZE(ops) && ops[header->op] != NULL)
+ audit_log_format(ab, "crypto_op=%s", ops[header->op]);
+ else
+ audit_log_format(ab, "crypto_op=%d", header->op);
+ audit_log_format(ab, " ctx=%d", crypto->context);
+ if (crypto->session != -1)
+ audit_log_format(ab, " session=%d", crypto->session);
+ if (crypto->operation != NULL) {
+ audit_log_format(ab, " operation=");
+ audit_log_string(ab, crypto->operation);
+ }
+ if (crypto->algorithm != NULL) {
+ audit_log_format(ab, " algo=");
+ audit_log_string(ab, crypto->algorithm);
+ }
+ if (crypto->key1 != -1) {
+ audit_log_format(ab, " key1=%d", crypto->key1);
+ if (crypto->key1_id_size > 0) {
+ audit_log_format(ab, " key1_id=");
+ audit_log_n_untrustedstring(ab, crypto->key1_id,
+ crypto->key1_id_size);
+ }
+ }
+ if (crypto->key2 != -1) {
+ audit_log_format(ab, " key2=%d", crypto->key2);
+ if (crypto->key2_id_size > 0) {
+ audit_log_format(ab, " key2_id=");
+ audit_log_n_untrustedstring(ab, crypto->key2_id,
+ crypto->key2_id_size);
+ }
+ }
+ audit_log_end(ab);
+}
+
+static void log_crypto_values(struct audit_context *context,
+ const struct audit_crypto_header *header)
+{
+ struct audit_buffer *ab;
+ const struct audit_crypto_values *crypto;
+ const struct audit_crypto_value *v;
+
+ crypto = (struct audit_crypto_values *)header;
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_CRYPTO_KEY_VALUE);
+ if (!ab)
+ return;
+ for (v = crypto->values; v < crypto->values + crypto->num_values; v++) {
+ audit_log_format(ab, " key_value_%c=", v->name);
+ audit_log_n_hex(ab, v->value, v->value_size);
+ }
+ audit_log_end(ab);
+}
+
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
const struct cred *cred;
int i, call_panic = 0;
struct audit_buffer *ab;
struct audit_aux_data *aux;
+ struct audit_crypto_header *crypto;
const char *tty;
/* tsk == current */
@@ -1442,6 +1586,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
call_panic = 1;
}
+ list_for_each_entry(crypto, &context->crypto, list) {
+ if (crypto->op != AUDIT_CRYPTO_OP_KEY_VALUE)
+ log_crypto_op(context, crypto);
+ else
+ log_crypto_values(context, crypto);
+ }
+
if (context->target_pid &&
audit_log_pid_context(context, context->target_pid,
context->target_auid, context->target_uid,
@@ -2486,6 +2637,89 @@ void __audit_log_capset(pid_t pid,
}
/**
+ * __audit_log_crypto_op - store information about an user-space crypto op
+ * @op: AUDIT_CRYPTO_OP_*
+ * @context: user-space context ID
+ * @session: session ID within @context, or -1
+ * @operation: more detailed operation description, or NULL
+ * @algorithm: algorithm (crypto API transform) name, or NULL
+ * @key1: ID of key 1 within @context, or -1
+ * @key1_id: user-space ID of key 1 set from user-space if @key1 != -1
+ * @key1_id_size: Size of @key1_id
+ * @key2: ID of key 2 within @context, or -1
+ * @key2_id: user-space ID of key 2 set from user-space if @key2 != -1
+ * @key2_id_size: Size of @key2_id
+ */
+int __audit_log_crypto_op(int op, int context, int session,
+ const char *operation, const char *algorithm,
+ int key1, void *key1_id, size_t key1_id_size,
+ int key2, void *key2_id, size_t key2_id_size)
+{
+ struct audit_crypto_op *ax;
+ struct audit_context *ctx = current->audit_context;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->hdr.op = op;
+ ax->context = context;
+ ax->session = session;
+ ax->operation = operation;
+ ax->algorithm = algorithm;
+ ax->key1 = key1;
+ if (key1 != -1) {
+ ax->key1_id_size = min(key1_id_size, sizeof(ax->key1_id));
+ memcpy(ax->key1_id, key1_id, ax->key1_id_size);
+ } else
+ ax->key1_id_size = 0;
+ ax->key2 = key2;
+ if (key2 != -1) {
+ ax->key2_id_size = min(key2_id_size, sizeof(ax->key2_id));
+ memcpy(ax->key2_id, key2_id, ax->key2_id_size);
+ } else
+ ax->key2_id_size = 0;
+ list_add_tail(&ax->hdr.list, &ctx->crypto);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__audit_log_crypto_op);
+
+/**
+ * __audit_log_crypto_op - store information about values of crypto keys
+ * @values: individual byte arrays describing the key. The "value" members
+ * must be allocated using kmalloc(), this function will take care of freeing
+ * them.
+ * @num_values: number of elements in @values
+ */
+void __audit_log_crypto_values(const struct audit_crypto_value *values,
+ size_t num_values)
+{
+ struct audit_crypto_values *ax;
+ struct audit_context *ctx = current->audit_context;
+ size_t i;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ goto free_values;
+
+ ax->hdr.op = AUDIT_CRYPTO_OP_KEY_VALUE;
+ BUG_ON(num_values > ARRAY_SIZE(ax->values));
+ ax->num_values = num_values;
+ for (i = 0; i < num_values; i++) {
+ ax->values[i].name = values[i].name;
+ ax->values[i].value = values[i].value;
+ ax->values[i].value_size = values[i].value_size;
+ }
+ list_add_tail(&ax->hdr.list, &ctx->crypto);
+ return;
+
+free_values:
+ for (i = 0; i < num_values; i++)
+ kfree(values[i].value);
+}
+EXPORT_SYMBOL_GPL(__audit_log_crypto_values);
+
+/**
* audit_core_dumps - record information about processes that end abnormally
* @signr: signal value
*